Golden Challenge: Adding Achievements

I’d like to get some feedback of the mistakes I might be doing or what would be a better solution.
I updated my addSubmitHandler to:

FormHandler.prototype.addSubmitHandler = function(fn) {
    // console.log('Setting submit handler for form');
    this.$formElement.on('submit', function(event) {
        event.preventDefault();
        var data = {};
        $(this).serializeArray().forEach(function(item) {
            data[item.name] = item.value;
        });

        if (data['size'] == "coffeezilla") {
            if (data['strengthLevel'] == 100) {
                if (data['flavor'] == "caramel") {
                     $('#myModal .modal-title').text('Dulce de Leche Unlocked')
                     $('#myModal .modal-body').text('WOW! Wanna put some dulce the leche in that coffee?')
                     $('#myModal').modal();
                }
                if (data['flavor'] == "almond") {
                  $('#myModal .modal-title').text('Almond Milk Unlocked')
                  $('#myModal .modal-body').text('WOW! Shall we change the order to Almond milk too?')
                  $('#myModal').modal();
                }
                if (data['flavor'] == "mocha") {
                  $('#myModal .modal-title').text('Extra Beans Unlocked')
                  $('#myModal .modal-body').text('WOW! Why not rather go with some Kenyan beans?')
                  $('#myModal').modal();
                }

                // $('#myModal').modal('show'); was not working here :frowning: 
            }
        }
        fn(data);

        this.reset();
        this.elements[0].focus();
    });
};

And in the index.html file I added:

    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">Modal title</h4>
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
          </div>
        </div>
      </div>
    </div>

Hi @pakpakpak! IIRC, we never add the bootstrap’s JavaScript code to CoffeeRun, which is where the .modal() method would come from.

Try adding a script tag for https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js to index.html, just after jquery.

RE better solution, here’s one way you could DRY up your solution with JavaScript objects:

var zilla = {
  caramel: {
    title: 'Dulce de Leche Unlocked',
    body: 'WOW! Wanna put some dulce the leche in that coffee?'
  },
  almond: {
    title: 'Almond Milk Unlocked',
    body: 'WOW! Shall we change the order to Almond milk too?'
  },
  mocha: {
    title: 'Extra Beans Unlocked',
    body: 'WOW! Why not rather go with some Kenyan beans?'
  }
};

var $modalTitle = $('#myModal .modal-title');
var $modalBody = $('#myModal .modal-body');

if (data.size == "coffeezilla" && data.strengthLevel == 100) {
  var copy = zilla[data.flavor];
  $modalTitle.text(copy.title);
  $modalBody.text(copy.body);
}

Thanks Jonathan!
I really like your solution, where does the data object come from.

Correct me if I’m wrong:

  1. I create the zilla object outside the .addSubmitHandler function, same as the modal variables.

  2. The SubmitFormHandler would look like this?

    FormHandler.prototype.addSubmitHandler = function(fn) {
    this.$formElement.on(‘submit’, function(event) {
    event.preventDefault();
    if (data.size == “coffeezilla” && data.strengthLevel == 100) {
    var copy = zilla[data.flavor];
    $modalTitle.text(copy.title);
    $modalBody.text(copy.body);
    }

         fn(data);
         $('#myModal').modal('show');
    
         this.reset();
         this.elements[0].focus();
    

    });

At the moment it is showing the modal but not populating the title and body with the right values.

Hi @pakpakpak! data is the same object you had in your solution code, so don’t forget to add back the code that creates it. But the rest of your solution looks correct!

I’ve been working on this challenge for some time now and just can’t get it right. I have the modal appearing just fine but it appears regardless of what options I pick. I’m guessing there is something wrong with the ‘if’ conditions but can’t find any errors. Any advice would be appreciated.

My JS:

FormHandler.prototype.addSubmitHandler = function (fn) {
console.log(‘Setting submit handler for form’);
this.$formElement.on(‘submit’, function (event) {
event.preventDefault();

var modalTitle = (’#myModal .modal-title’);
var modalBody = (’#myModal .modal-body’);

if (data.size == "coffeezilla" && data.strengthLevel == 100) {
  $modalTitle.text(title);
  $modalBody.text(body);
}

$(’#myModal’).modal(‘show’);

Are there any other approaches I could take?

I’m a few years late to the party but I really liked this book and found this challenge really nice for consolidating the stuff taught in the chapter. Here is my solution:

I decided I’d stick with the book’s ways of modularizing code (as opposed to newer import/export). Mainly to learn how and when to use this (which I was struggling with)

First a new module, achievementhandler.js

(function(window) {
  'use strict';
  const App = window.App || {};
  const $ = window.jQuery;

  function AchievementHandler() {
    console.log('Initializing AchievementHandler');
    this._arrayOfAchievers = [];
    this._pendingAchiever = undefined;

    this.$noButton = $('#modalNo');
    this.$yesButton = $('#modalYes');

    this.$emailInput = $('#emailInput');

    this.$achieverOptions = $('#achieverOptions');

    this.$resetAndSubmitButtons = $('[type="reset"], [type="submit"]');

  }

  AchievementHandler.prototype.addAchiever = function(email) {
    console.log('Adding superuser - invoking addAchiever');
    this._arrayOfAchievers.push(email);
    console.log('Updated list of superusers:');
    console.log(this._arrayOfAchievers);
  };

  AchievementHandler.prototype.getAchievers = function() {
    return this._arrayOfAchievers;
  };

  AchievementHandler.prototype.handleModal = function(email) {
    this._pendingAchiever = email;

    const isAlreadyAchiever = this._arrayOfAchievers.some(function(el) {
      return el === this._pendingAchiever;
    }.bind(this));

    if (!isAlreadyAchiever) {
      $('#achievementModal').modal('show');
    }
  };

  AchievementHandler.prototype.addModalButtonHandler = function() {
    console.log('Initializing modal button handler');

    this.$yesButton.on('click', function(event) {
      event.preventDefault();

      console.log('yes clicked - pending superuser added to array');
      this._arrayOfAchievers.push(this._pendingAchiever);
      this._pendingAchiever = undefined;

      console.log('Updated list of superusers: ');
      console.log(this._arrayOfAchievers);

      $('#achievementModal').modal('hide');
    }.bind(this));

    this.$noButton.on('click', function(event) {
      event.preventDefault();

      console.log('no clicked - purging pendning superuser');
      this._pendingAchiever = undefined;

      $('#achievementModal').modal('hide');
    }.bind(this));

    this.$resetAndSubmitButtons.on('click', function() {
      $(this.$achieverOptions).css("display", "none");
    }.bind(this));

  };

  AchievementHandler.prototype.addEmailInputHandler = function() {
    this.$emailInput.on('input', function(event) {
      console.log($(this.$emailInput).val());
      this._arrayOfAchievers.forEach(function(email) {
        if ($(this.$emailInput).val() === email) {
          console.log('Achiever Detected!');
          $(this.$achieverOptions).css("display", "block");
        }
      }.bind(this))
    }.bind(this));
  };

  App.AchievementHandler = AchievementHandler;
  window.App = App;
})(window);

And these lines added to main.js:

const AchievementHandler = App.AchievementHandler;

const achievementHandler = new AchievementHandler();

achievementHandler.addModalButtonHandler();
achievementHandler.addEmailInputHandler();

/* update the call to addSubmitHandler with a second callback function */
formHandler.addSubmitHandler(truckOne.createOrder.bind(truckOne), achievementHandler.handleModal.bind(achievementHandler));
  

Then inside index.html I added the following just before the buttons:

<fieldset id="achieverOptions" style="display: none;">
            <legend class="col-form-label col-12 pt-0">Superuser options:</legend>
            <div class="form-check">
              <input class="form-check-input" type="checkbox" id="methylphenidate" name="methylphenidate" value="yes">
              <label class="form-check-label" for="methylphenidate">Methylphenidate</label>
            </div>
            <div class="form-check">
              <input class="form-check-input" type="checkbox" id="lsd" name="lsd" value="yes">
              <label class="form-check-label" for="lsd">LSD</label>
            </div>
            <div class="form-check">
              <input class="form-check-input" type="checkbox" id="alcohol" name="alcohol" value="yes">
              <label class="form-check-label" for="alcohol">Alcohol (20%)</label>
          </fieldset>

and also in index.html a section with the code for the modal:

<section>

    <div class="modal fade" id="achievementModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
      <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalCenterTitle">Achievement Unlocked!</h5>
          </div>
          <div class="modal-body">
            <h6>Achievement: <strong>Sleep is overrated</strong></h6>
            <p>Do you want to unlock this achievement and add your email to our list of superusers? This unlocks extra options for your next order.</p>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal" id="modalNo">No</button>
            <button type="button" class="btn btn-primary" id="modalYes">Yes</button>
          </div>
        </div>
      </div>
    </div>

  </section>

Also used script tags to import the new achievement handler.js and the bootstrap js file.

And lastly, in formhandler.js I updated addSubmitHandler (I had four sizes from the previous challenge)

FormHandler.prototype.addSubmitHandler = function(callback, passEmailToAchievementHandler) {

    console.log('Initializing submit handler for form.');

    this.$formElement.on('submit', function(event) {

      event.preventDefault();

      const data = {};

      $(this).serializeArray().forEach(function(item) {
        data[item.name] = item.value;
        console.log(item.name + ' is: ' + item.value);
      });

      console.log(data);

      if (data['size'] === 'extremo' && data['strength'] === '100') {
        console.log('Superuser detected - email: ' + data['emailAddress']);


        // Pass email to achievemnthandler
        passEmailToAchievementHandler(data['emailAddress']);

      }

      callback(data);
      this.reset();
      this.elements[0].focus();
    });
  };