Quantcast
Viewing all articles
Browse latest Browse all 28

Re-Learning Backbone.js – Events (Pub-Sub)

 

Since we are here to learn about Backbone.js, we are going to use the built in feature of Backbone called Events. Backbone.js Events is a feature that provides a Pub-Sub. As usually I’m going to attempt to keep this a simple as possible. To provide a basic understanding of Pub-Sub, we will not work with views, models or collections; we will only work with Backbone Event. My goal is to keep this extremely simple, and the concepts that you learn here can assistance you when build more complex, maintainable, extensible, flexible, and plus other bilities websites.

Here’s an example of a protypical webpage. In a webpage like this, anytime the user does an action on the webpage, such as login, search, sort and other other action, the page refreshes. One reason we are learning Backbone.js is so that we can provide a better experience to the user by providing single page applications (SPA).

If we created an application like the following with Backbone.js, there could be many views (items in red boxes). In a webpage like this, the developer my define in code that the Search view is aware of the Movie List view, or the Login view is aware of the Recommendation view. For example, if the user logs-in, the Login view will directly notify the Recommendation view of the login. This is fine for simple SPA. But if this is done on a complex website like Trello, which is created with Backbone.js, maintainability and extensibility and other bilities may become an issue.

For example, what happens if management wants to replace the Recommendation view with a new Friends View. Now the developer must change the code in the Login view to update the Friends view. In this example the developer has tightly coupled the Login view to the Recommendation view. Probably not the best decision the developer has made.

Image may be NSFW.
Clik here to view.

Here’s a few quotes:

“Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically” Gang of Four book on Design patterns

“Publishers are loosely coupled to subscribers, and need not even know of their existence. With the topic being the focus, publishers and subscribers are allowed to remain ignorant of system topology. Each can continue to operate normally regardless of the other. In the traditional tightly coupled client–server paradigm, the client cannot post messages to the server while the server process is not running, nor can the server receive messages unless the client is running. Many pub/sub systems decouple not only the locations of the publishers and subscribers, but also decouple them temporally. A common strategy used by middleware analysts with such pub/sub systems is to take down a publisher to allow the subscriber to work through the backlog (a form of bandwidth throttling).” WikiPedia – http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern

“The general idea behind the Observer pattern is the promotion of loose coupling (or decoupling as it’s also referred as). Rather than single objects calling on the methods of other objects, an object instead subscribes to a specific task or activity of another object and is notified when it occurs. Observers are also called Subscribers and we refer to the object being observed as the Publisher (or the subject). Publishers notify subscribers when events occur.” Addy Osmani – http://msdn.microsoft.com/en-us/magazine/hh201955.aspx

This is somewhat techno babble, but once you understand the Pub-Sub or Observer pattern, these definitions make a lot of sense. It doesn’t help out a lot here, but hopefully we get you to the point where these definitions do make sense.

So forget about the example above. We are going to use a simpler example. Lets assume we have a security system. The security system is made-up of 3 key parts: a door (publisher), control panel (hub), and customer service (subscriber). Anytime the door (publisher) opens, the customer service (subscriber) will be notified. But we don’t want to tightly couple these objects together. We needed a mediator that manages the subscribers and the publishers, and this is where the control panel (hub) comes in.

I don’t believe “hub” is a technical term you will associate with PubSub or Observer pattern, but I believe “hub” helps to describe these patterns better.

In the following example we are going to create a controlPanel object. We are going to create a customerServie object. The customerService object is going to subscribe “Door:Open” event. When the “Door:Open” event is triggered, then call the “alert” method on the customerService object. In this example the door is not going to trigger the event; we will trigger the event manually. We just want to make sure everything is working before we move to the next step.

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

<html >
<head>
    <title></title>
    <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script>
   	<script src="/scripts/underscore.js" type="text/javascript"></script>
	<script src="/scripts/backbone.js" type="text/javascript"></script>
</head>
<body>
    <script type="text/javascript">
        var ControlPanel = function () {
            this.events = _.extend({}, Backbone.Events);
        };

        var CustomerService = function (name) {
            this.name = name;
            //should use Prototype for this funciton, but this will work.
            this.alert = function (msg) {
                console.log(name + " alerted; " + msg);
            };
        };

        var controlPanel = new ControlPanel();
        var george = new CustomerService("George");

        controlPanel.events.on("door:open", george.alert);

        controlPanel.events.trigger("door:open", "test");
    </script>
</body>
</html>

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

To start out, we have a “ControlPanel” class that has a one property called events. We are using underscore (_) to copy Backbone.Events functionality to the “events” property of the control panel. If you don’t understand this, see Backbone.js documentation on events at http://backbonejs.org/#Events.

Next we create a “CustomerService” class. This is extremely simple. This class has a property and method. There’s nothing special here.

Next we create a “controlPanel” object from the “ControlPanel” class.

We also create a “CustomerService” object call “George”

Now, we tell the “controlPanel” “events” that anytime you see the event “door:open” call “george.alert”. The “on” method is used to subscribe to an event. So, “george.alert” is subscribing to the “door:open” event.

To validate this works, we manually call “trigger” on “events”, and pass in “door:open”. We also pass “test” as an argument that will be passed to the method “george.alert”. The key here is the string “door:open”. The “events” uses “door:open” to identify if there are any subscribers that needs to be notify. If it finds a subscriber, then call the method(s) associated with the event.

Here’s something interesting. In the browser console I type in “controlPanel.events._callbacks["door:open"].next.callback“.

Image may be NSFW.
Clik here to view.

I’m not going to discuss this, but I believe it’s something good to chew on.

 

***********************************************************************************************

It’s time for the Door to trigger the event.

The primary thing I want you to get out of this example is that the Front Door is not aware of the George, and George is not aware of the front door, but the front door can trigger George events.

Image may be NSFW.
Clik here to view.

<html >
<head>
    <title></title>
    <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script>
   	<script src="/scripts/underscore.js" type="text/javascript"></script>
	<script src="/scripts/backbone.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
        //Dynamic Prototype Pattern - Professional JavaScript for Web Developers - Obect Creation
        var CustomerService = function (name) {
            this.name = name;
            //should use Prototype for this funciton, but this will work.
            this.alert = function (msg) {
                console.log(name + " alerted; " + msg);
            };
        };

        var ControlPanel = function () {
            this.events = _.extend({}, Backbone.Events);
        };

        var Door = function (controlPanel, name) {
            this.name = name
            this.controlPanel = controlPanel;
            this.open = function () {
                this.controlPanel.events.trigger("door:open", name);
            }
        };

        //create objects
        var controlPanel = new ControlPanel();
        var george = new CustomerService("George");

        controlPanel.events.on("door:open", george.alert);

        var frontDoor = new Door(controlPanel, "frontDoor");
        frontDoor.open();
    </script>
</body>
</html>

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

This example is not much different than the previous example, other than the frontDoor(publisher) is triggering the event. The hub is forwarding the event to “george” the subscriber by calling “george.alert”.

 

*************************************************************************************************

Now what happens if we have two Doors (publishers) triggering “door:open” events?

Image may be NSFW.
Clik here to view.

<html >
<head>
    <title></title>
    <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script>
   	<script src="/scripts/underscore.js" type="text/javascript"></script>
	<script src="/scripts/backbone.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
        //Dynamic Prototype Pattern - Professional JavaScript for Web Developers - Obect Creation
        var CustomerService = function (name) {
            this.name = name;
            //should use Prototype for this funciton, but this will work.
            this.alert = function (msg) {
                console.log(name + " alerted; " + msg);
            };
        };

        var ControlPanel = function () {
            this.events = _.extend({}, Backbone.Events);
        };

        var Door = function (controlPanel, name) {
            this.name = name
            this.controlPanel = controlPanel;
            this.open = function () {
                this.controlPanel.events.trigger("door:open", name);
            }
        };

        //create objects
        var controlPanel = new ControlPanel();
        var george = new CustomerService("George");

        controlPanel.events.on("door:open", george.alert);

        var frontDoor = new Door(controlPanel, "frontDoor");
        frontDoor.open();

        var sideDoor = new Door(controlPanel, "sideDoor");
        sideDoor.open();
    </script>
</body>
</html>

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

All we did was add an additional Door called “sideDoor”(publisher) and called its open method. Now the “george”(subscriber) is notified of the “frontDoor” and the “sideDoor” opening. Still the doors(publisher) has no knowledge of the “george” (subscriber). And it was very easy to add an additional publisher.

 

*******************************************************************************************************

Now what happens if we have multiple subscribers listening to “door:open” events.

Image may be NSFW.
Clik here to view.

<html >
<head>
    <title></title>
    <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script>
   	<script src="/scripts/underscore.js" type="text/javascript"></script>
	<script src="/scripts/backbone.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
        //Dynamic Prototype Pattern - Professional JavaScript for Web Developers - Obect Creation
        var CustomerService = function (name) {
            this.name = name;
            //should use Prototype for this funciton, but this will work.
            this.alert = function (msg) {
                console.log(name + " alerted; " + msg);
            };
        };

        var ControlPanel = function () {
            this.events = _.extend({}, Backbone.Events);
        };

        var Door = function (controlPanel, name) {
            this.name = name
            this.controlPanel = controlPanel;
            this.open = function () {
                this.controlPanel.events.trigger("door:open", name);
            }
        };

        //create objects
        var controlPanel = new ControlPanel();
        var george = new CustomerService("George");

        controlPanel.events.on("door:open", george.alert);

        var chris = new CustomerService("Chris");
        controlPanel.events.on("door:open", chris.alert);

        var frontDoor = new Door(controlPanel, "frontDoor");
        frontDoor.open();

        var sideDoor = new Door(controlPanel, "sideDoor");
        sideDoor.open();
    </script>
</body>
</html>

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

In this example, all we did was add a new “CustomerService” object called “chris”(subscriber). And we told the “controlPanel”, anytime the “door:open” event occurs, call “chris.alert”.

In the results we can see the “chris” and “george” are notified of “open:door” event for “frontDoor” and “sideDoor”

*****************************************************************************************

Now what happens when we unsubscribe “george” “open:door” from the “controlPanel”?

Image may be NSFW.
Clik here to view.

<html >
<head>
    <title></title>
    <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script>
   	<script src="/scripts/underscore.js" type="text/javascript"></script>
	<script src="/scripts/backbone.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
        //Dynamic Prototype Pattern - Professional JavaScript for Web Developers - Obect Creation
        var CustomerService = function (name) {
            this.name = name;
            //should use Prototype for this funciton, but this will work.
            this.alert = function (msg) {
                console.log(name + " alerted; " + msg);
            };
        };

        var ControlPanel = function () {
            this.events = _.extend({}, Backbone.Events);
        };

        var Door = function (controlPanel, name) {
            this.name = name
            this.controlPanel = controlPanel;
            this.open = function () {
                this.controlPanel.events.trigger("door:open", name);
            }
        };

        //create objects
        var controlPanel = new ControlPanel();
        var george = new CustomerService("George");

        controlPanel.events.on("door:open", george.alert);

        var chris = new CustomerService("Chris");
        controlPanel.events.on("door:open", chris.alert);

        var frontDoor = new Door(controlPanel, "frontDoor");
        frontDoor.open();

        var sideDoor = new Door(controlPanel, "sideDoor");
        sideDoor.open();

        console.log("");

        controlPanel.events.off("door:open", george.alert)
        sideDoor.open();
    </script>
</body>
</html>

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

Here we tell the events that if you are aware of an event called “door:open” and it assigned to “george.alert”, please unsubscribe.

We can see in the results that when we called “sideDoor.Open” that “george.alert” did not get called, but “chris.alert” did get called.

I believe this enough for this session. Hopefully you understand Pub-Subs and the quotes above will make a little more sense.

 


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 28

Trending Articles