Jquery Design Patterns - Sample Chapter
Jquery Design Patterns - Sample Chapter
P U B L I S H I N G
pl
C o m m u n i t y
$ 39.99 US
25.99 UK
Sa
m
Thodoris Greasidis
ee
D i s t i l l e d
E x p e r i e n c e
Thodoris Greasidis
Preface
Since its introduction in 2006, the jQuery library has made DOM traversals and
manipulations much easier. This has resulted in the appearance of Web pages with
increasingly complex user interactions, thus contributing to the maturing of Web as a
platform capable of supporting large application implementations.
This book presents a series of best practices that make the implementation of
Web applications more efficient. Moreover, we will analyze the most important
Design Patterns that Computer Science has to offer, which can be applied to
Web development. In this way, we will learn how to utilize techniques that are
thoroughly used and tested in other fields of programming, which were initially
created as generic methods to model solutions of complex problems.
In jQuery Design Patterns, we will analyze how various Design Patterns are
utilized in the implementation of jQuery and how they can be used to improve the
organization of our implementations. By adopting the Design Patterns demonstrated
in this book, you will be able to create better organized implementations that
resolve large problem categories faster. Moreover, when used by a developer team,
they can improve the communication between them and lead to homogenous
implementation, where every part of the code is easily understood by others.
Preface
Chapter 2, The Observer Pattern, will teach you how to respond to user actions
using the Observer Pattern. It also demonstrates how to use Event Delegation as a
way to reduce the memory consumption and complexity of the code that handles
dynamically injected page elements. Finally, it will teach you how to emit and listen
for Custom Events in order to achieve greater flexibility and code decoupling.
Chapter 3, The Publish/Subscribe Pattern, will teach you how to utilize the Pub/Sub
Pattern to create a central point to emit and receive application-level events,
as a way to decouple your code and business logic from the HTML that is used
for presentation.
Chapter 4, Divide and Conquer with the Module Pattern, demonstrates and compares
some of the most commonly used Module Patterns in the industry. It will teach
you how to structure your application in small independent Modules using
Namespacing, leading to expandable implementations that follow the Separation
of Concerns principle.
Chapter 5, The Facade Pattern, will teach you how to use the Facade Pattern to
wrap complex APIs into simpler ones that are a better match for the needs of
your application. It also demonstrates how to change parts of your application,
while keeping the same module-level APIs and avoid affecting the rest of
your implementation.
Chapter 6, The Builder and Factory Patterns, explains the concepts of and the
differences between the Builder and Factory Patterns. It will teach you how
and when to use each of them, in order to improve the clarity of your code by
abstracting the generation of complex results into separate dedicated methods.
Chapter 7, Asynchronous Control Flow Patterns, will explain how jQuery's Deferred and
Promise APIs work and compare them with the classical Callbacks Pattern. You will
learn how to use Promises to control the the execution of asynchronous procedures
to run either in an order or parallel to each other.
Chapter 8, Mock Object Pattern, teaches you how to create and use Mock Objects and
Services as a way to ease the development of your application and get a sense of its
functionality, long before all its parts are completed.
Chapter 9, Client-side Templating, demonstrates how to use the Underscore.js and
Handlebars.js templating libraries as a better and faster way to create complex
HTML structures with JavaScript. Through this chapter, you will get an overview
of their conventions, evaluate their features, and find the one that best matches
your taste.
Preface
Chapter 10, Plugin and Widget Development Patterns, introduces the basic concepts and
conventions of jQuery Plugin development and analyzes the most commonly used
design patterns, so that you will be able to identify and use the best match for any
use case.
Chapter 11, Optimization Patterns, guides you with the best tips to create a highly
efficient and robust implementation. You will be able to use this chapter as a
checklist of best practices that improve the performance and lower the memory
consumption of your applications, before moving them to a production environment.
The Publish/Subscribe
Pattern
In this chapter, we will showcase the Publish/Subscribe Pattern, a design pattern
quite similar to the Observer Pattern but with a more distinct role that is a better fit
for more complex use cases. We will see how it differs from the Observer Pattern
and how jQuery adopted some of its concepts and brought them to its Observer
Pattern implementation.
Later, we will proceed and rewrite our previous chapter's example using this pattern.
We will use this pattern's benefits to add some extra features and also reduce the
coupling of our code with the elements of the web page.
In this chapter, we will:
Learn how it differs and what advantages it has over the Observer Pattern
Rewrite and extend the example from Chapter 2, The Observer Pattern,
using this pattern
[ 49 ]
[ 50 ]
Chapter 3
[ 52 ]
Chapter 3
[ 53 ]
To apply this pattern, we will only need to change the code in the JavaScript file with
our new implementation. In the following code snippet, we can see how the code
was changed in order to adapt to the Publisher/Subscriber Pattern:
$(document).ready(function() {
window.broker = $('.dashboardContainer');
$('#categoriesSelector').change(function() {
var $selector = $(this);
var message = { categoryID: $selector.val() };
broker.trigger('dashboardCategorySelect', [message]);
});
broker.on('dashboardCategorySelect', function(event, message) {
var $dashboardCategories = $('.dashboardCategory');
var selectedIndex = +message.categoryID;
var $selectedItem = $dashboardCategories.eq(selectedIndex)
.show();
$dashboardCategories.not($selectedItem).hide();
});
$('.dashboardCategory').on('click', 'button', function() {
var $button = $(this);
var message = { categoryName: $button.text() };
broker.trigger('categoryItemOpen', [message]);
});
[ 54 ]
Chapter 3
broker.on('categoryItemOpen', function(event, message) {
var boxHtml = '<div class="boxsizer"><article class="box">' +
'<header class="boxHeader">' +
message.categoryName +
'<button class="boxCloseButton">✖' +
'</button>' +
'</header>' +
'Information box regarding ' + message.categoryName +
'</article></div>';
$('.boxContainer').append(boxHtml);
});
$('.boxContainer').on('click', '.boxCloseButton', function() {
var boxIndex = $(this).closest('.boxsizer').index();
var message = { boxIndex: boxIndex };
broker.trigger('categoryItemClose', [message]);
});
broker.on('categoryItemClose', function(event, message) {
$('.boxContainer .boxsizer').eq(message.boxIndex).remove();
});
});
[ 55 ]
In order to implement the category selector, we are first observing the <select>
element for the change event. When the selected category changes, we create
our message using a plain JavaScript object with the value of the selected
<option> stored in the categoryID property. Then, we publish it in the
dashboardCategorySelect topic using the jQuery jQuery.fn.trigger() method
on our broker. This way, we move from a UI element event to a message with
application semantics that contains all the required information. Right below, in our
subscriber's code, we are using the jQuery.fn.on() method on our broker with the
dashboardCategorySelect topic as a parameter (our custom event), just like we
would do to listen for a simple DOM event. The subscriber then uses the categoryID
from the received message, just like we did in the implementation of the previous
chapter, to display the appropriate category items.
Following the same approach, we split the code that handles adding and closing
information boxes in our dashboard in publishers and subscribers. For the needs of
this demonstration, the message of the categoryItemOpen topic contains just the
name of the category we want to open. However, in an application where the box
content is retrieved from a server, we would probably use a category item ID instead.
The subscriber then uses the category item name from the message to create and
insert the requested information box.
Similarly, the message for the categoryItemClose topic contains the index of the
box that we want removed. Our publisher uses the jQuery.fn.closest() method
to traverse the DOM and reach the child elements of our boxContainer element and
then uses the jQuery.fn.index() method to find its position among its siblings.
The subscriber then uses jQuery.fn.eq() and the boxIndex property from the
received message to filter and remove only the requested information box from
the dashboard.
In a more complex application, instead of the box index, we can
associate each information box element with a newly retrieved
jQuery.guid using a mapping object. This will allow our publisher
to use that guid in the message instead of the (DOM-related) element
index. The subscriber will then search the mapping object for that
guid in order to locate and remove the appropriate box.
Since we are trying to demonstrate the advantages of the Pub/Sub
Pattern, this implementation change was not introduced in order to
ease the comparison with the Observer Pattern and is instead left as a
recommended exercise for the reader.
[ 56 ]
Chapter 3
For the counter implementation, we will need to add some extra HTML
to our page and also create and reference a new JavaScript file to hold the
counter implementation:
...
</section>
<div style="margin-left: 5px;">
Open boxes:
<output id="dashboardItemCounter">1</output>
</div>
<section class="boxContainer">
...
[ 57 ]
In the HTML page of the example, we will need to add an extra <div> element
to hold our counter and some description text. For our counter, we are using an
<output> element, which is a semantic HTML5 element ideal to present results of
user actions. The browser will use it just like a normal <span> element, so it will
appear right next to its description. Also, since there is initially a hint box open in
our dashboard, we use a 1 for its initial content:
$(document).ready(function() {
broker.on('categoryItemOpen categoryItemClose',
function (event, message) {
var $counter = $('#dashboardItemCounter');
var count = parseInt($counter.text());
if (event.type === 'categoryItemOpen') {
$counter.text(count + 1);
} else if (event.type === 'categoryItemClose' && count > 0) {
$counter.text(count - 1);
}
});
});
For the counter implementation itself, all we need to do is add an extra subscriber to
the dashboard's broker, which is globally available to other JavaScript files loaded
in the page, since we have attached it to the window object. We are simultaneously
subscribing to two topics, by passing them space delimited to the jQuery.fn.on()
method. Right after this, we locate the counter <output> element that has the
ID dashboardItemCounter and parse its text content as a number. In order to
differentiate our action, based on the topic that the message has received, we use the
event object that jQuery passes as the first parameter to our anonymous function,
which is our subscriber. Specifically, we use the type property of the event object
that holds the topic name of the message that was received and based on its value,
we change the content of the counter.
For more information on the event object that jQuery provides, you
can visit http://api.jquery.com/category/events/eventobject/.
Similarly, we could also rewrite the code that prevents accidental double-clicks on
the category item buttons. All that is needed is to add an extra subscriber for the
categoryItemOpen topic and use the categoryName property of the message to
locate the pressed button.
[ 58 ]
Chapter 3
[ 59 ]
For more information, you can visit the documentation page at http://docs.
jquery.com/Namespaced_Events and the article at https://css-tricks.com/
namespaced-events-jquery/ from the CSS-Tricks website.
Summary
In this chapter, we were introduced to the Publish/Subscribe Pattern. We saw
its similarities with the Observer Pattern and also learned its benefits by doing
a comparison of the two. We analyzed how the more distinct roles and the extra
features that the Publish/Subscribe Pattern offers make it an ideal pattern for more
complex use cases. We saw how jQuery developers adopted some of its concepts
and brought them to their Observer Pattern implementation as custom events.
Finally, we rewrote the example from the previous chapter using the Publish/
Subscribe Pattern, adding some extra features and also achieving greater
decoupling between the different parts and page elements of our application.
Now that we have completed our introduction to how the Publish/Subscribe Pattern
can be used as a first step to decouple the different parts of an implementation,
we can move on to the next chapter where we will be introduced to the Module
Pattern. In the next chapter, we will learn how to separate the different parts of an
implementation into independent modules and how to use namespacing to achieve
better code organization and define a strict API to achieve communication between
the different modules.
[ 60 ]
www.PacktPub.com
Stay Connected: