List of Figures
Chapter 1. What is a single-page application?
Figure 1.1. In a traditional web application, each new view (HTML page) is constructed on the server.
Figure 1.2. In an SPA, the presentation layer moves to the client-side code, and transactions never require a browser refresh.
Figure 1.3. The HTML shell is the beginning structure. It has no content yet, only an empty DIV tag.
Figure 1.4. Subsections of the shell are called regions. A region’s content is provided by a view.
Figure 1.5. In traditional site design, each HTML file is a complete HTML page.
Figure 1.6. In an SPA design, one complete HTML file contains placeholders for the HTML fragments stored in view files.
Figure 1.7. A view is the marriage of data and one or more templates.
Figure 1.8. Views are attached to the DOM dynamically, usually as a result of user navigation, beneath the initial container
DIV or one of its regions.
Figure 1.9. Views in an SPA are seamlessly swapped (through DOM manipulation) for a given area of the screen, giving the user
a more desktop-like feel.
Figure 1.10. CSS, HTML, and JavaScript are the building blocks for the single-page application. There’s no special language
to learn and no browser plugins required.
Figure 1.11. Using regions, an SPA’s views can be placed so that it looks exactly like a traditional web page.
Figure 1.12. Keeping the presentation layers segregated based on their purpose allows designers and developers to work in
parallel. It also allows developers to test, maintain, and deploy code more effectively.
Figure 1.13. Using the module pattern limits the scope of variables and functions to the module itself. This helps avoid many
of the pitfalls associated with global scope in a single-page application.
Chapter 2. The role of MV* frameworks
Figure 2.1. Indiscriminately interweaving JavaScript, HTML, and CSS makes your project more difficult to manage as it grows.
Figure 2.2. The data of your application can be separated from its representation in the UI.
Figure 2.3. The MVC design pattern has been used for many years in the development of graphical user interfaces.
Figure 2.4. MVP is a variation of MVC. With this pattern, the view is the entry point, but its logic is in the presenter.
Figure 2.5. In MVVM, the ViewModel is aware of changes in both the model and the view and keeps the two in sync.
Figure 2.6. Data from models are combined (bound) with reusable templates to create views that make up the SPA’s UI.
Figure 2.7. Screen capture of the online directory. The user enters information in the form on the left. Valid entries appear
in a list on the right.
Figure 2.8. The application’s data in our online directory project is just an array of employee models. Each model is an object
that contains the employee information we’ll see onscreen.
Figure 2.9. Screen capture of the online directory. Here you see that two instances of the employee model have been added
to the list.
Figure 2.10. The fully rendered template, created by a template engine
Figure 2.11. In this example, a SPAN tag’s contents are being updated dynamically as the user types into an INPUT field.
Chapter 3. Modular JavaScript
Figure 3.1. In a module, the outer function encapsulates its functionality. There’s no direct access to internal variables
and functions. Access is regulated via functions in the object literal it returns.
Figure 3.2. Returning customers correctly greeted with a simple message and no mention of a discount
Figure 3.3. Suddenly everyone’s being told they’re in for a big discount!
Figure 3.4. Without a module to limit the scope of each function, both are added to the same global scope, causing a name
conflict.
Figure 3.5. You use dot notation, without a var, to declare a submodule. What you’re really doing is adding a property called
customer, which itself contains a module.
Figure 3.6. Using modules, our welcome message is once again correct!
Figure 3.7. Now that each getStatus() function lives in its own module, there are no more name conflicts.
Figure 3.8. The module pattern makes it clear how others should use your code.
Figure 3.9. The module pattern helps organize code into units of functionality rather than individual functions.
Figure 3.10. The outer function of the pattern creates a local scope for variables and functions. This gives the module a
way to achieve privacy for internal code.
Figure 3.11. An object literal is returned. Its functions have access to the module’s internal variables and functions. This
gives calling code regulated access to the module’s functionality.
Figure 3.12. The trailing parentheses cause the anonymous function of the module pattern to be invoked immediately, returning
the object literal.
Figure 3.13. A closure keeps any variables or functions referenced in the IIFE alive, even after execution.
Figure 3.14. This assignment creates the module’s namespace.
Figure 3.15. The outer parentheses aren’t required.
Figure 3.16. RequireJS has no dependencies to download. You need only the require.js file.
Figure 3.17. The module loader correctly downloads and manages our AMD modules and dependencies. The require directive in
main.js declares a dependency that instructs RequireJS to fetch the displayUtil module. The displayUtil module, in turn, has
a dependency on the counter module that gets dynamically loaded by the module loader.
Chapter 4. Navigating the single page
Figure 4.1. In traditional web-page navigation, complete pages are sent back to the browser, triggering a refresh to display
the new content.
Figure 4.2. In an SPA, the client-side router assumes control of navigation, allowing the SPA to display new views instead
of complete pages.
Figure 4.3. An overview of the SPA navigation process and the role of the router
Figure 4.4. Router configuration entries serve as instructions for what happens when a route’s path matches a part of the
browser’s URL.
Figure 4.5. The fragment identifier
Figure 4.6. For this example, you’ll create a basic website for a university department.
Figure 4.7. Clicking the Contact Us link produces a new fragment identifier in the browser’s URL.
Figure 4.8. Passing manderson via a route parameter results in the correct office hours being displayed.
Chapter 5. View composition and layout
Figure 5.1. Our sample project tracks the status of orders for a fictitious medical supply company and includes a layout that’s
more complex and diverse than you’ve previously dealt with.
Figure 5.2. The template’s HTML forms an initial structure, but CSS refines its look and feel.
Figure 5.3. Regions give you a physical area in the UI where your views can be displayed. Within a region, views can be fixed
or dynamically swapped.
Figure 5.4. CSS is used to define the physical attributes of the regions in your layout, as well as to define their relationship
with other regions in the UI.
Figure 5.5. How regions and views are configured impacts view composition and ultimately the layout.
Figure 5.6. Regions can also be used in views, if you need to nest a view (or views) inside another view.
Figure 5.7. Example of a simple route
Figure 5.8. Example of a route with multiple views
Figure 5.9. The base layout begins with a top region and a bottom region.
Figure 5.10. You’ll finish up the base layout with a region for navigation and a region for content.
Figure 5.11. The base layout with styles applied
Figure 5.12. The layout’s header after styles have been applied
Figure 5.13. Your layout after both the header and navigation view are rendered
Figure 5.14. Your layout after the default route displays the open orders in the content region
Figure 5.15. To compose the customer information feature, you’re placing additional regions within the main view itself to
include the related but separate contact and order history views.
Figure 5.16. What your three views look like when displayed in the content region
Figure 5.17. The result of the customer information route with each view highlighted
Figure 5.18. The nested shipping view with its own URL
Chapter 6. Inter-module interaction
Figure 6.1. As your project grows, your code base become less and less manageable if you put all your variables and functions
in the global namespace.
Figure 6.2. The module forms a protective barrier around your code. Variables and functions declared within the module are
private.
Figure 6.3. Each public function in the API (left of the colon) has a corresponding reference to a private object inside the
module (right of the colon).
Figure 6.4. The assigned external variable can be used to indirectly reference the internal objects.
Figure 6.5. Modules can have multiple functions but should ideally have a single, overall purpose.
Figure 6.6. Modules can be reused in other modules, other features, or even throughout the entire application.
Figure 6.7. In the observer pattern, each observer is notified whenever something changes in the object it’s observing.
Figure 6.8. The messaging module uses pub/sub to publish messages, via an intermediary service, to any subscribers in the
application.
Figure 6.9. Our sample project is an online store to sell used video games.
Figure 6.10. Upon arrival, users are greeted with a welcome message and can immediately begin to search for games.
Figure 6.11. High-level view of what happens when a user searches for a game title
Figure 6.12. The search controllers module uses the search services module to perform the searches. The search services module
is its only dependency.
Figure 6.13. The search services module uses the app data module as a data source and the messaging services module to broadcast
the number of search results.
Figure 6.14. Search results are displayed to the user, along with a brief user alert about the number of records found. Each
search result is a link to display the item’s details.
Figure 6.15. The messaging service is a generic utility, blindly broadcasting any message it’s given. The only module listening
in this case is the user alerts module.
Figure 6.16. High-level view of the product display process
Figure 6.17. The product display services module finds the correct product information by using the selected game’s ID.
Figure 6.18. Your data and the components of the pricing module are used to calculate the price discount for the game selected.
Figure 6.19. The resulting view after a matching game is found and a discount has been applied to the game’s price
Chapter 7. Communicating with the server
Figure 7.1. JavaScript objects are converted to JSON and added to the request body for the request. In response, the server
sends back the updated cart as JSON via the response body.
Figure 7.2. With MV* frameworks, where your model extends those of the framework, you automatically inherit abilities from
the parent, such as the ability to make server requests.
Figure 7.3. Frameworks that provide server communication, but don’t provide a model to extend, will most likely provide a
data source object instead.
Figure 7.4. With callbacks, control passes from the save() function to either the success() function or the error() function
after the process has completed.
Figure 7.5. A promise has three mutually exclusive states: pending, fulfilled, and rejected.
Figure 7.6. The product display page now features a button to add the item to the shopping cart.
Figure 7.7. The shopping cart view allows the user to modify the cart’s contents.
Chapter 8. Unit testing
Figure 8.1. Our sample project calculates the amount of the tip and the total amount to be paid. It also rates the tip given.
Figure 8.2. A unit test is a low-level, focused test created during development that’s quick to execute and offers the least
lag in getting test results.
Figure 8.3. Focus unit tests on the lowest level of the application’s logic.
Figure 8.4. In this design, all the logic is hidden behind this one vague API.
Figure 8.5. Smaller, specialized functions are a better fit for unit testing.
Figure 8.6. With traditional unit testing, tests are written after the code has been created.
Figure 8.7. In test-driven development, tests are written before the code is created.
Figure 8.8. The test directory will have a similar structure but is usually kept separate from the application’s source.
Figure 8.9. QUnit test report after your first unit test is run
Figure 8.10. QUnit test report with a failed test
Figure 8.11. QUnit test report shows tests grouped together as a test module.
Figure 8.12. QUnit testing against a Backbone.js model
Figure 8.13. QUnit test report showing tests run for an AngularJS service
Figure 8.14. Your test directory after adding your second JavaScript testing framework
Chapter 9. Client-side task automation
Figure 9.1. Common uses for JavaScript-based task runners
Figure 9.2. Gulp.js is able to pipe together data streams for processing.
Appendix A. Employee directory example walk-through
Figure A.1. Screen capture of the online directory. The user enters information in the form on the left. Valid entries appear
in a list on the right.
Figure A.2. Directory structure for the Backbone.js version of the application
Figure A.3. Directory structure for the Knockout version of the application
Figure A.4. Directory structure for the AngularJS version of the application
Appendix B. Review of the XMLHttpRequest API
Figure B.1. Your request to get the shopping cart contents is successful. You use a GET request, passing a cart ID of 123
via a URL parameter.
Figure B.2. The server responds with your shopping cart’s JSON-formatted text. You can see that the cart has no items.
Figure B.3. You use the POST method to send complex request objects in the form of JSON-formatted text to the server from
your SPA.
Figure B.4. After the new item is posted to the server, you have one game in your shopping cart.
Appendix C. Chapter 7 server-side setup and summary
Figure C.1. The shopping cart has a list of items that holds a number of games ranging from 0 to n.
Figure C.2. The ErrorMessage object is used to relay errors back to the UI.
Figure C.3. Complete project workspace
Appendix D. Installing Node.js and Gulp.js
Figure D.1. Installing Gulp.js