State variables

Look out for

Checking if an element has a class.

Resolve by

Using a variable to keep track of state.

$toggleButton.on( 'click', function() {
  $modal.toggleClass('is-open');
  // check state by checking DOM
  if ( $modal.hasClass('is-open') ) {
    $toggleButton.text('Close');
  } else {
    $toggleButton.text('View more');
  }
});

Edit this demo on CodePen

// use state variable to keep track
var isModalOpen = false;

$toggleButton.on( 'click', function() {
  isModalOpen = !isModalOpen;
  $modal.toggleClass('is-open');
  if ( isModalOpen ) {
    $toggleButton.text('Close');
  } else {
    $toggleButton.text('View more');
  }
});

Edit this demo on CodePen

Demo

Edit demo Modal - state variables on CodePen

Video

Lesson

jQuery makes it so easy to read and manipulate the DOM that developers are led to use the DOM for state. What do I mean by state? State is the current condition of the site. Which button is selected? Is the modal open? Has the request finished loading? All these questions are being asked about the site's state.

Let's look at an example. It's a simple modal. Clicking a button toggles the modal open or closed, and it toggles the text of the button from View more when closed to Close when open.

In the JS, we determine the state of the modal, whether its open or closed, by checking if its element has the class is-open.

var $toggleButton = $('.toggle-button');
var $modal = $('.modal');

$toggleButton.on( 'click', function() {
  $modal.toggleClass('is-open');
  if ( $modal.hasClass('is-open') ) {
    $toggleButton.text('Close');
  } else {
    $toggleButton.text('View more');
  }
});

(Look how lovely it is with its $modal and $toggleButton jQuery object variables.)

And it works! So what's the issue?

When working with jQuery, you can get into a jQuery mindset. You start thinking of all of programming in jQuery terms: get elements, and do something with them. But jQuery exists within JavaScript, a programming language that has its own lower-level concepts. And with these concepts, we can write better code.

The issue with checking the class, is that we don't need to read the DOM to know what the state is. Our program can keep track of its own state. We can do this with a variable.

At the top, let's add a variable isModalOpen and set it to false.

var isModalOpen = false;

Within the click event callback function, we'll switch isModalOpen to its opposite, false to true, or true to false.

var isModalOpen = false;

$toggleButton.on( 'click', function() {
  isModalOpen = !isModalOpen;
  ...
});

Now our program knows if the modal is open or not. So we can use the variable within the conditional.

var isModalOpen = false;

$toggleButton.on( 'click', function() {
  isModalOpen = !isModalOpen;
  $modal.toggleClass('is-open');
  if ( isModalOpen ) {
    $toggleButton.text('Close');
  } else {
    $toggleButton.text('View more');
  }
});

Nice! By adding a state variable we have removed a check of the DOM. We have abstracted the behavior out of the HTML so our JavaScript is more flexible.

But more importantly, you can start to grasp the potential of using variables to keep track of stuff.

Or not. So we added a variable, but the code is actually longer and it functionally works exactly the same. Is that really an improvement?

Removing multiple classes

Let's look at another example. This time, we're not just dealing with a simple on-off switch, but multiple values.

Look out for

Removing all possible classes an element could have.

Resolve by

Using a variable to store the one thing that is active.

$('.color-button-group button').on( 'click', function() {
  $swatchGroup.removeClass('red orange yellow green blue purple');
  selectedColor = $( this ).text();
  $swatchGroup.addClass( selectedColor );
});

Edit this demo on CodePen

var selectedColor;

$('.color-button-group button').on( 'click', function() {
  $swatchGroup.removeClass( selectedColor );
  selectedColor = $( this ).text();
  $swatchGroup.addClass( selectedColor );
});

Edit this demo on CodePen

Edit demo Color buttons - state variable on CodePen

This example has several buttons. Clicking a button adds a color class, which changes the color of several elements with CSS.

Because this example uses CSS to change color, it needs to remove any previous color class. Currently, the previous class is removed by removing all potential color classes.

$swatchGroup.removeClass('red orange yellow green blue purple');

Functionally, This code works just fine. But it's duplicating the HTML. This is a problem. Any change in the colors in the HTML means you'll have to make a similar change in the JavaScript. Having the colors hard-coded in JS also means that code can't be easily reused in another place, for another potential set of colors and swatches.

Let's add a variable, selectedColor, to keep track of the selected color. We'll declare the variable selectedColor at the top. Then use it to remove the previous class. Then update selectedColor from the element in the event. And finally use the updated value to add the clicked color.

var selectedColor;

$('.color-button-group button').on( 'click', function() {
  $swatchGroup.removeClass( selectedColor );
  selectedColor = $( this ).text();
  $swatchGroup.addClass( selectedColor );
});

Now this code has no reference to the colors used in the HTML. You can add, remove, and change the colors in the HTML and the JS code will work just the same.

Wrap up

That's what state variables are all about. They allow you to keep your HTML structure out of your JavaScript. So you can think of the JavaScript just as its behavior, not as the content its works with.

These are simple examples, but their lessons are important. Up until now, you likely have thought of writing JavaScript in terms of what's on the page. By using variables, you are opening a new door in understanding JavaScript. It's not just what's on the page, but what's inside your program.