Creating the Row Constructor

You cannot create the markup in index.html for the checklist items, because they need to be added after the page has already been rendered, in response to form submissions. Instead, you will add a Row constructor to the CheckList module.

The Row constructor will be in charge of creating all the DOM elements necessary to represent a single coffee order, including the checkbox and text description. But the Row constructor will not be exported to the App namespace. It will only be used internally by one of the CheckList.prototype methods.

Add the Row constructor in checklist.js, just before the App.CheckList = CheckList; statement. It should accept an argument called coffeeOrder that will be the same data that is sent to Truck.prototype.createOrder.

...
    this.$element = $(selector);
    if (this.$element.length === 0) {
      throw new Error('Could not find element with selector: ' + selector);
    }
  }

  function Row(coffeeOrder) {
    // Constructor code will go here
  }

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

Creating DOM elements with jQuery

Your Row constructor will use jQuery to build DOM elements. You will declare variables for the individual elements that make up a checklist item. Then the constructor will append them together into a subtree of DOM elements, as shown in Figure 11.4. The CheckList will take that subtree and attach it to the page’s DOM tree as a child of the [data-coffee-order="checklist"] element.

Figure 11.4  CheckList creates a row and appends its DOM elements

CheckList creates a row and appends its DOM elements

(The “[39x]” in the order description represents the caffeine strength.)

The DOM subtree created by the Row constructor in Figure 11.4 is the equivalent of the following markup:

<div data-coffee-order="checkbox" class="checkbox">
  <label>
    <input type="checkbox" value="[email protected]">
    tall mocha iced coffee, ([email protected]) [39x]
  </label>
</div>

A <div> with a checkbox class is used to house your <label> and an <input> element. The checkbox class will apply the appropriate Bootstrap styles to the <div>. The data-coffee-order attribute will be used in your JavaScript when you need to trigger the click action on the checkbox.

Note that the type attribute of your <input> is also checkbox. This tells the browser to draw the input as a checkbox form element. A plain text description of the order comes right after the <input>. The <label> wraps both the checkbox input and the plain text description. This turns the text and the input into a click target for the checkbox.

You will create the <label>, <div>, and <input> elements one at a time. Then you will manually place the elements inside of one another to create a DOM subtree that you will attach to the live DOM (the DOM tree currently shown on the page). You will also create a string that holds the text description of the order, like “tall mocha iced coffee, ([email protected]) [39x].”

To create these elements, you will use jQuery’s $ function. Up to now, you only used the $ function to select elements from the DOM, but it can also be used to create them.

First, you are going to create the <div> by calling the $ function in the Row constructor in checklist.js. Pass it two arguments describing the DOM element you want it to create. Make the first argument a string with the HTML tag of the DOM element, in this case '<div></div>'. Make the second argument an object that specifies the attributes that jQuery should add to the <div>. The key/value pairs of the object literal are translated into the attributes of the new element.

The result is a DOM element created by jQuery that you will assign to a new variable called $div. This will not be an instance variable (that is, it is just $div and not this.$div). It is prefixed with the $ to denote that it is not a plain DOM element, but one that jQuery created a reference to.

Make it so in checklist.js.

...
  function Row(coffeeOrder) {
    // Constructor code will go here
    var $div = $('<div></div>', {
      'data-coffee-order': 'checkbox',
      'class': 'checkbox'
    });
  }
...

Notice that your two property names are in single quotation marks. You might assume from this that you should always use single quotes around property names when creating a DOM element using jQuery, but actually that is not the case. Property names that have special characters (like the dash) need to be in quotes, otherwise it is considered a syntax error. Valid characters that can be used in a property name (or a variable name) without single quotes are the letters of the alphabet, numerical digits, the underscore (_), and the dollar sign ($).

'class' is in single quotes because “class” is a JavaScript-reserved word, so single quotes are needed to prevent the browser from reading it as JavaScript (which would also result in a syntax error).

Next, create the <label> element in checklist.js with the $ function but without an object argument. It does not need any extra attributes.

...
  function Row(coffeeOrder) {
    var $div = $('<div></div>', {
      'data-coffee-order': 'checkbox',
      'class': 'checkbox'
    });

    var $label = $('<label></label>');
  }
...

Now, create the <input> element for the checkbox by calling the $ function and passing it the HTML for an <input> tag. For the second argument, specify that the type should be a checkbox and that the value should be the email address of the customer. Because none of these property names use special characters, you do not need to put them in single quotes.

...
  function Row(coffeeOrder) {
    var $div = $('<div></div>', {
      'data-coffee-order': 'checkbox',
      'class': 'checkbox'
    });

    var $label = $('<label></label>');

    var $checkbox = $('<input></input>', {
      type: 'checkbox',
      value: coffeeOrder.emailAddress
    });
  }
...

By setting the value to the customer’s email address, you are associating the checkbox with the customer’s coffee order. Later, when you add the click handler, you can identify which coffee order was clicked based on the email address in the value attribute.

The last thing to create is the text description that will be displayed next to the checkbox. You will build a string for this by concatenating the pieces using the += operator.

Create a variable called description in checklist.js. Set it to the size property of the order, then add a comma and a space. If a flavor was provided, concatenate it using +=. Then concatenate the coffee, emailAddress, and strength values. The emailAddress should be wrapped in parentheses and the strength should be in brackets and followed by the letter “x.” (The parentheses and brackets are not for syntactic purposes, just for formatting the text.)

...
  function Row(coffeeOrder) {
    ...

    var $checkbox = $('<input></input>', {
      type: 'checkbox',
      value: coffeeOrder.emailAddress
    });

    var description = coffeeOrder.size + ' ';
    if (coffeeOrder.flavor) {
      description += coffeeOrder.flavor + ' ';
    }

    description += coffeeOrder.coffee + ', ';
    description += ' (' + coffeeOrder.emailAddress + ')';
    description += ' [' + coffeeOrder.strength + 'x]';
  }
...

The += concatenation operator does addition and assignment in one step. That means that the following two lines of code are equivalent:

description += coffeeOrder.flavor + ' ';
description = description + coffeeOrder.flavor + ' ';

You now have all the individual parts of the checklist item and are ready to append them to one another (Figure 11.5).

Figure 11.5  Assembling the individual DOM elements into a subtree

Assembling the individual DOM elements into a subtree

You will do this in three steps:

  1. Append the $checkbox to the $label

  2. Append the description to the $label

  3. Append the $label to the $div

More generally, you will build the subtree by working from left to right, bottom to top. This approach is similar to how you developed your CSS for Ottergram in Chapter 3, by beginning with the smallest, innermost elements and working your way up.

In checklist.js, use the jQuery append method to connect the elements together. This method accepts either a DOM element or a jQuery-wrapped collection and adds it as a child element.

...
  function Row(coffeeOrder) {
    ...
    description += coffeeOrder.coffee + ', ';
    description += ' (' + coffeeOrder.emailAddress + ')';
    description += ' [' + coffeeOrder.strength + 'x]';

    $label.append($checkbox);
    $label.append(description);
    $div.append($label);
  }
...

Your Row constructor can now create and assemble the subtree of elements using the coffee order data passed in. However, because Row will be used as a constructor and not as a regular function, it cannot simply return this subtree. (In fact, constructors should never have a return statement; JavaScript automatically returns a value for you when you use the keyword new with a constructor.)

Instead, make the subtree available as a property of the instance by assigning it to this.$element in checklist.js. (This name was chosen just to follow the convention used with your other constructors; it does not have any special meaning by itself.)

...
  function Row(coffeeOrder) {
    ...
    $label.append($checkbox);
    $label.append(description);
    $div.append($label);

    this.$element = $div;
  }
...

The Row constructor is ready for work. It can build up the DOM subtree necessary to represent an individual coffee order with a checkbox. It holds on to that DOM representation in an instance variable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.206.69