Video Course

Build an Interactive JavaScript Food Menu: Lesson 11 of 14

Showing Modal Based on Store Flag

Up Next

Add to Cart and Show Items in Modal

Autoplaying in 7 seconds!

Cancel

First thing we need to do is make sure that an event is fired when the cart icon in the top right is clicked. This is another weird case where it is being added dynamically and adding event listeners doesn't always work. We will add the event listener in more of a jQuery-like style. Let's create a file at src/js/setup_listeners.js. Put the following in it.

import { $ } from './helpers';

export default function (store) {
  $('#cart-icon').on('click', () => {
    store.trigger('TOGGLE_SHOW_CART');
  });
}

Here we are saying "Hey. When the cart icon is clicked, trigger a TOGGLE_SHOW_CART event on the store. We are passing in the store so that we can trigger events on it.

You may have noticed that we use an on method on the object returned from using our $ helper. Let's add this in our helpers.js file.

function on(event, cb) {
  elements.forEach(ele => {
    ele.addEventListener(event, cb);
  });
}

return {
  on,
  children,
};

It simply loops through each element and adds an event listener like we specified.

We need to tell our index.js to import this file and call that function. First import the function at the top.

import setupListeners from './setup_listeners';

Then call the function after we trigger the SET_ITEMS event.

fetch('food.json')
  .then(res => res.json())
  .then(resBody => {
    const body = document.querySelector('body');
    body.insertBefore(app(store), body.childNodes[0]);
    store.trigger('SET_ITEMS', { items: resBody });
    setupListeners(store);
  });

Now that the event will fire, we need to change the state in the reducer. Add the following to the reducer in index.js.

case 'TOGGLE_SHOW_CART':
  return Object.assign({}, state, {
    cartVisible: !state.cartVisible,
  });

This case uses Object.assign like our other one. However, this one sets the cartVisible attribute to the opposite value. Now let's make the modal listen for this event and update the modal when it is fired. First we need to pass it into the modal in app.js.

const modalEle = modal(store);

Next, we need to have the modal listen for it.

import { addClass, addId, button, div, h1, i, p, section, text, ul } from '../builders';
import { $ } from '../helpers';
import modalItem from './modalItem';

export default function modal(store) {
  const close = addId(addClass(i(), 'fa', 'fa-times', 'close'), 'close');
  const title = addClass(h1(text('Cart')), 'title');

  const cartContainer = addId(div(p(text('Your cart is empty.'))), 'cart-items');

  const checkoutButton = addClass(button(text('Checkout')), 'button', 'is-fullwidth');

  const modalContainer = addClass(div(close, title, cartContainer, checkoutButton), 'modal-container');

  const modalEle = addId(addClass(section(modalContainer), 'modal'), 'modal');

  store.on('TOGGLE_SHOW_CART', ({ cartVisible }) => {
    const ele = $('#modal');
    if (cartVisible) {
      ele.addClass('show');
    } else {
      ele.removeClass('show');
    }
  });

  return modalEle;
}

We subscribe to the TOGGLE_SHOW_CART event. In the callback, we grab the element using our handy $ helper. Then we check if the cartVisible variable in state is true or not. If it is true, that means we need to show the modal. So we add a class of show. If not, then we remove the class. This class changes the display property on the modal to block. This lives in our CSS.

We need to add the addClass and removeClass methods to our helper.

function addClass(klass) {
  elements.forEach(ele => {
    ele.classList.add(klass);
  });
}

function removeClass(klass) {
  elements.forEach(ele => {
    ele.classList.remove(klass);
  });
}

return {
  on,
  children,
  addClass,
  removeClass,
};

If you check our work in the browser, you will see that you are able to show and hide the modal by clicking the cart icon. However, there is also an "X" on the modal that we want to use to close it. This is simple. We need to add an event listener to it and tell it to trigger the TOGGLE_SHOW_CART event. We can add this to our other on call in setup_listeners.js.

$('#cart-icon, #close').on('click', () => {
  store.trigger('TOGGLE_SHOW_CART');
});

Boom! That's it. Try it out in the browser. Show the modal using the cart icon and close it using the "X."

Next time, we are going to add functionality to add items to our cart.

Chris Sevilleja

164 posts

Co-founder of Scotch.io. Slapping the keyboard until something good happens.