CoffeeRun is off to a good start. It has two JavaScript modules that handle its internal logic and an HTML form styled with Bootstrap. In this chapter, you will write a more complex module that connects the form to the logic, allowing you to use the form to enter coffee orders.
Recall from Chapter 2 that browsers communicate with
servers by sending requests for information for a particular URL. Specifically,
for every file that the browser needs to load, it sends a GET
request to the server for that file.
When the browser needs to send information to a server, such as
when a user fills out and submits a form, the browser takes the form data and puts it
in a POST
request. The server receives the request, processes the data,
and then sends back a response (Figure 10.1).
In CoffeeRun, you will not need to send the form data to a server for processing. Your Truck and DataStore modules serve the same purpose as traditional server-side code. Their job is to handle the business logic and data storage for your application.
Because this code lives in the browser and not on a server, you need to capture the data from the form before it goes out. In this chapter you will create a new module called FormHandler to do just that. In addition, you will add the jQuery library to CoffeeRun to help you with your work. As you build out CoffeeRun over the next few chapters, you will use more of jQuery’s powerful features.
The FormHandler module will prevent the browser from trying to send form data to a server. Instead, it will read the values from the form when the user clicks the Submit button. Then it will send that data to a Truck instance, using the createOrder method you wrote in Chapter 8 (Figure 10.2).
Create a new file called formhandler.js in your
scripts folder and add a <script>
tag for it in index.html.
... </form> </div> </div> </section> <script src="scripts/formhandler.js" charset="utf-8"></script> <script src="scripts/datastore.js" charset="utf-8"></script> <script src="scripts/truck.js" charset="utf-8"></script> <script src="scripts/main.js" charset="utf-8"></script> </body> </html>
Like your other modules, FormHandler will use an IIFE to encapsulate the
code and attach a constructor to the window.App
property.
Open scripts/formhandler.js and create an IIFE. Inside the IIFE,
create an App
variable. Assign it the existing value
of window.App
. If window.App
does not exist yet, assign it an empty object literal. Declare a
FormHandler constructor function, and export it
to the window.App
property.
(function (window) { 'use strict'; var App = window.App || {}; function FormHandler() { // Code will go here } App.FormHandler = FormHandler; window.App = App; })(window);
So far, this code follows the familiar pattern you used in your Truck and DataStore modules. It will be different soon, though, in that it will import and use jQuery to do its work.
The jQuery library was created by John Resig in 2006. It is one of the most popular general-purpose open-source JavaScript libraries. Among other things, it provides convenient shorthands for DOM manipulation, element creation, server communication, and event handling.
It is useful to be familiar with jQuery, because there is so
much code that has been written using it. Also, many libraries
have copied jQuery’s conventions.
In fact, jQuery has directly influenced the standard DOM API
(document.querySelector
and
document.querySelectorAll
are two examples
of this influence).
jQuery will not be covered in depth right now. Instead, aspects of it will be introduced as needed to help you build more complex parts of CoffeeRun. Should you want to explore jQuery further, check out the documentation at jquery.com.
As you did with Bootstrap, you will add a copy of jQuery to your project from cdnjs.com. Go to cdnjs.com/libraries/jquery to find version 2.1.4 and copy its address. (There may be a more recent version available, but you should use 2.1.4 for CoffeeRun to avoid any compatibility issues.)
Add jQuery in a <script>
tag in index.html.
... </div> </section> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js" charset="utf-8"></script> <script src="scripts/formhandler.js" charset="utf-8"></script> <script src="scripts/datastore.js" charset="utf-8"></script> <script src="scripts/truck.js" charset="utf-8"></script> <script src="scripts/main.js" charset="utf-8"></script> ...
Save index.html.
FormHandler will import
jQuery the same way that it is importing App
.
The reason for doing this is to make it explicit that your
module is using code that is defined elsewhere.
This is a best practice for coordinating with team members
and for future maintenance.
In formhandler.js, create a local variable
named $ and then assign it the value
window.jQuery
.
(function (window) { 'use strict'; var App = window.App || {}; var $ = window.jQuery; function FormHandler() { // Code will go here } App.FormHandler = FormHandler; window.App = App; })(window);
When you added the jQuery <script>
tag, it created a function named
jQuery as well as a variable, named
$, pointing to the function.
Most developers prefer to use $
in their code. In keeping with that practice, you are
importing window.jQuery
and assigning it to the local
variable $.
Wondering why $ is used for the variable name? JavaScript variable names can contain letters, numbers, the underscore (_), or the dollar sign ($). (They can only start with letters, underscores, or dollar signs, though – not numbers.) The creator of jQuery chose the $ variable name because it is short and unlikely to be used by any other code in a project.
Your FormHandler module should be usable with
any <form>
element. To achieve this, the FormHandler
constructor will be passed a selector matching
the <form>
element in
index.html.
Update formhandler.js to add a parameter called
selector
to the FormHandler constructor. Throw an
Error if it is not passed in.
(function (window) { 'use strict'; var App = window.App || {}; var $ = window.jQuery; function FormHandler(selector) {// Code will go hereif (!selector) { throw new Error('No selector provided'); } } App.FormHandler = FormHandler; window.App = App; })(window);
Error is a built-in type that lets you formally signal that there is an unexpected value or condition in your code. For now, your Error instance will simply print out your message on the console.
Save and try instantiating a new FormHandler
object without passing it an argument (Figure 10.3).
(Remember to start browser-sync
, if it is not already running.)
This is the first step in making FormHandler more reusable. In Ottergram, you created variables for the selectors you used in your DOM code. You will not be doing that with the FormHandler module. Instead, you will use the selector that was passed in to the constructor and use jQuery to find the matching elements.
jQuery is most often used for finding elements in the DOM. To do that, you call the jQuery $ function and pass it a selector as a string. In fact, you use it the same way you have been using document.querySelectorAll (although jQuery works differently under the hood, as we will explain in a moment). It is common to refer to this as “selecting elements from the DOM” with jQuery.
Declare an instance variable named $formElement in formhandler.js. Then find a matching element in the DOM using that selector and assign the result to this.$formElement.
(function (window) { 'use strict'; var App = window.App || {}; var $ = window.jQuery; function FormHandler(selector) { if (!selector) { throw new Error('No selector provided'); } this.$formElement = $(selector); } App.FormHandler = FormHandler; window.App = App; })(window);
Prefixing a variable with $
is a
sign that the variable refers to elements selected using jQuery.
This prefix is not a requirement when using jQuery, but it is a
common convention used by many front-end developers.
When you use jQuery’s $ function to select elements, it does not return references to DOM elements, the way that document.querySelectorAll does. Instead, it returns a single object, and the object contains references to the selected elements. The object also has special methods for manipulating the collection of references. This object is called a “jQuery-wrapped selection” or “jQuery-wrapped collection.”
Next, you want to make sure that the selection successfully retrieved an element from the DOM. jQuery will return an empty selection if it does not find anything – it will not throw an error if the selector does not match anything. You will need to check manually, because FormHandler cannot do its work without an element.
The length
property
of a jQuery-wrapped selection tells you how many elements were matched.
Update formhandler.js to check the length
property of this.$formElement.
If it is 0
, throw an Error
.
(function (window) { 'use strict'; var App = window.App || {}; var $ = window.jQuery; function FormHandler(selector) { if (!selector) { throw new Error('No selector provided'); } this.$formElement = $(selector); if (this.$formElement.length === 0) { throw new Error('Could not find element with selector: ' + selector); } } App.FormHandler = FormHandler; window.App = App; })(window);
Your FormHandler constructor can be
configured to work with any <form>
element based on the selector
passed in. Also, it keeps a reference to that <form>
element as an
instance variable. This ensures that your code will not make
make unnecessary trips to the DOM. This is a performance best
practice. (The alternative is to call $
over and over, which re-selects the same elements each time.)
3.145.87.161