Logo

JsonData

  • Archive
  • RSS
  • Ask me anything

BackboneBlog: A Reference Project

To help round out my blog series on Backbone, I wrote a little reference app a few months back to help me keep my bearings whilst building large scale client applications.

At the time, I was contracting with a local startup that was building a fairly complex client/server web app. The front end was all written in Backbone (and the back end in Java/Spring). On this project, our dev team was distributed. Half of our team was working in a remote location, with the other half located in Scottsdale.

As I became more involved in the project, I began to realize that we needed a bit more cohesion in our client side coding efforts. I think I was a little late to the game on that, but I think (hope) some found it helpful. Anyway, here it is: BackboneBlog.

It’s a little out of date at this point. I need to update the Require.js implementation to the latest version. That’ll allow me to cut more unnecessary code via the (lib).require.js module shims for the projects that don’t support AMD, along with a few other odds and ends.

I hope you find it helpful. Feel free to fork it and play around with it. If you end up finding any bugs or adding anything to it, please shoot me a pull request. :)

    • #backbone.js
    • #underscore.js
    • #handlebars
    • #jquery
    • #MVP
    • #require.js
  • 8 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Event aggregation with Backbone

This is the sixth post in my blog series on Backbone.js. If you haven’t had a chance yet, make sure to catch up on the first 5:

  1. Hey, check out my Backbone
  2. Aligning my Backbone
  3. Backbone Routers Are Configuration
  4. Grokking Backbone Views
  5. Async Template Loading with Backbone

In my second post I talked about how I employ the MVP design pattern to keep components of my JavaScript apps nicely decoupled. Interestingly, since that post, there have been some rumblings on the interwebs calling this pattern ‘MOVE’. I think you’ll see it popping up more and more as it gains momentum.

In my first post, I also mentioned that when you look at Backbone through an “MVC lense”, initially people often make a few incorrect assumptions on how the app should work. This is often based on their understanding of how a server-side MVC app functions. It certainly was in my case. In this post I’m going to cover how this approach differs from the common understanding of server-side MVC.

Getting Pub/Sub

Mind blown

One piece of knowledge hit me last fall as I was writing the Facebook authentication app (in Backbone/CoffeeScript) for the latest version of CentralAZ.com. Here it is: JavaScript apps written on the client are not stateless. If you’ve written lots of client apps in your career, then this probably isn’t a huge surprise to you, but this little tidbit of knowledge totally blew my mind. My focus had been on the server for so long, that I projected a lot of what I knew about ASP.NET MVC and Rails onto Backbone. This post by Derek Bailey really drove that point home for me. In a Backbone application, the model is a representation of the current application state.

mind === 'blown'
> true

In Backbone, the preferred method of cross-communication between app components or modules is to use the Observer pattern, also commonly referred to as “pub/sub”. In Backbone, you get a very nice way implementing this pattern via extending Backbone.Events. This allows different components of an app to send messages or listen for messages being broadcast by an event aggrigator without having to know where those events are coming from.

How does that work?

To illustrate, we’ll assume each JS module lives in its own file and that the app is composed when the page loads via AMD (Asyncronous Module Definition) in Require.js. It’s not important to fully grok AMD to understand how the following code samples work together, the important thing to understand, though, is that each of these JS snippets represent separate JS files. They’re fully encapsulated and know nothing of each other, beyond the dependencies they request in the first parameter of the define() function call.

// Define a module to return an event aggrigator object extended from Backbone.Events.
// Let's call this events.js.
define(['underscore', 'backbone'], function (_, Backbone) {
    return _.extend({}, Backbone.Events);
});

Let’s pretend we have an app that allows a user to authenticate and view their own personal information. In this sample app, we’ll be listening for 2 different events. We want to listen for an event that signifies that a user intends to log out of their account. But we also want to know when the user has actually been logged out by the server. In Backbone apps, it’s considered good practice to namespace your events by object or model type. An event name can be any string value, but in order to keep things organized and easy to understand, we’ll use this convention:

events.trigger('object:property');

// or

events.trigger('object:action');

OK, so now that we’ve got our event aggregation object, we’ll listen for the user:loggedOut event in the initialize method of our router. When a user clicks on a “logout” button, the user should be redirected to the home page once the server successfully logs them out. We’ll take a pessmistic approach to this event, meaning that we’ll wait to make sure “logout” actually happened on the server before we redirect.

// Defining a router module, called router.js
define(['backbone', 'events', 'presenter'], function (Backbone, events, Presenter) {

    var router = Backbone.Router.extend({
        routes: {
            '': 'index',
            'myprofile': 'userProfile'
        },
        initialize: function (options) {
            // Wiring up the presenter just like we did in a previous post...
            this.presenter = new Presenter(options);

            // _.bindAll is important here, because `this` will not be the current 
            // instance of our router when it the events bound below get triggered.
            _.bindAll(this);

            // Here's the magic that binds a function to the `user:loggedOut` event
            events.on('user:loggedOut', this.onLogout);
        },

        // Here's our event handler. It accepts a user model object, but we're not 
        // going to use it here...
        onLogout: function (user) {
            // Call Backbone.Router.navigate here to tell our router to update the
            // URL and log browser history, sending the user to the home page. The
            // empty string in this call corresponds to the empty string in the
            // routes declaration above.
            this.navigate('', true);
        },

        // Route handler definitions that get bound based on routes defined above
        index: function () {
            this.presenter.showIndex();
        },
        userProfile: function () {
            this.presenter.showUserProfile();
        }
    });

    return router;
});

Additionally, we’ll have a view called authenticationView.js that listens for the user:loggedOut as well, that will fire when the user is successfully logged out by the server.

// Defining a authentication view module called authenticationView.js
define(['backbone', 'events', 'templateManager'], 
    function (Backbone, events, TemplateManager) {

    var view = Backbone.View.extend({
        template: 'userAuthentication',
        className: 'user-authentication',
        initialize: function (options) {
            this.model = options.model;
            _.bindAll(this);

            // When the user logs out, we just want to re-render this view
            events.on('user:loggedOut', this.render);
        },
        // Nothing extra special going on in our view's render method. Our template will
        // check the model's `isAuthenticated` flag to see if the user is currently 
        // logged in.
        render: function () {
            var that = this;
            TemplateManager.get(this.template, function (tmp) {
                var html = tmp(that.model.toJSON());
                that.$el.html(html);
                that.rendering();
            });

            return this;
        },

        // In a previous post I covered having your views clean up after
        // themselves to avoid memory leaks. Here's a good example of this
        // in practice. In `onClose`, we'll unsubscribe from `user:loggedOut`
        onClose: function () {
            events.off('user:loggedOut');
        }
    });

    return view;
});

Here’s what our corresponding Handlebars client-side template would look like. We’ll call it userAuthentication.html.

{{#if isAuthenticated}}
<a href="#">Howdy {{name}}!</a>
{{else}}
<a href="#">Log In</a>
{{/if}}

We’ll also have a second view that has a “Log Out” button that will fire the user:loggingOut event to get things kicked off.

// Defining our userProfile.js module.
define(['backbone', 'events', 'templateManager'], 
    function (Backbone, events, TemplateManager) {

    var view = Backbone.View.extend({
        template: 'userProfile',
        className: 'user-profile',
        events: {
            'click #log-out', 'logoutClicked'
        },
        initialize: function (options) {
            this.model = options.model;
            _.bindAll(this);
        },
        render: function () {
            var that = this;
            TemplateManager.get(this.template, function (tmp) {
                var html = tmp(that.model.toJSON());
                that.$el.html(html);
                that.rendering();
            });

            return this;
        },
        logoutClicked: function () {
            // Fire the `user:loggingOut` event to kick things off. Make sure to pass 
            // along a reference of the current user.
            events.trigger('user:loggingOut', this.model);
            return false;
        }
    });

    return view;
});

You might be asking yourself, “That’s great, but how does the user actually get logged out?”

Great question. We’ll just wire up another listener on the presenter to tell the model to log itself out.

// For posterity, here's what our presenter.js would look like.
define(['events', 'userModel' 'indexView', 'userProfileView'], 
    function (events, UserModel, IndexView, UserProfileView) {

    var Presenter = function (options) {
        this.model = options.model || new UserModel();
        _.bindAll(this);

        // We'll set up a handler here to listen for `user:loggingOut`
        events.on('user:loggingOut', this.onLogout);
    };

    Presenter.prototype.showView = function (view) {
        if (this.currentView) {
            this.currentView.close();
        }

        this.currentView = view;
        $('#container').append(this.currentView.render().$el);
    };

    Presenter.prototype.showIndex = function () {
        var view = new IndexView({ model: this.model });
        this.showView(view);
    };

    Presenter.prototype.showUserProfile = function () {
        var view = new UserProfileView({ model: this.model });
        this.showView(view);
    };

    // Here's our handler for `user:loggingOut`. We'll have the user model call logout 
    // on itself.
    Presenter.prototype.onLogout = function (user) {
        var promise = user.logout();

        // `user.logout` returns a jQuery deferred, so we can bind a handler to trigger 
        // the `user:loggedOut` event when the ajax call completes successfully.
        promise.done(function () {
            events.trigger('user:loggedOut', user);
        });
    };

    return Presenter;
});

Finally, to complete the story, we’ll wire up our user model so it knows how to to log itself out.

// Defining a module for our user model called user.js
define(['backbone', 'events'], function (Backbone, events) {
    var model = Backbone.Model.extend({
        initialize: function (options) {
            _.bindAll(this);
        },
        logout: function () {
            var that = this,
                promise = $.trafficCop({
                    type: 'POST',
                    url: '/user/logout',
                    data: this.toJSON()
                });

            // Bind a callback to our promise to set the `isAuthenticated` flag 
            // to `false` when logout completes successfully.
            promise.done(function () {
                that.set({ isAuthenticated: false }, { silent: true });
            });

            return promise;
        }
    });

    return model;
});

But why not just use jQuery’s built in event pool?

It’s true that jQuery has its own version of Backbone.Events that looks the same, and is implemented, in much the same way. The Backbone team, I believe, decided to roll their own version for two good reasons:

  1. If I understand correctly, when Backbone was first being written, jQuery’s event pooling employed a DOM-based eventing system (e.g. - document.addEventListener, etc). Since then, jQuery has moved to an object-based eventing system similar to Bacbkone’s.
  2. In order to keep the dependency tree light, Backbone’s only dependency is Underscore. There’s not a hard dependency on jQuery (nor should there be). Using jQuery’s eventing system would require a hard dependency on jQuery.

What’s with _.bindAll being called everywhere?

A lot of people new to Backbone may not be too cozy with Underscore (yet). Basically, calling _.bindAll(this) will ensure that all methods of the object passed in will have the correct context of this bound to its calling context. Doing this basically guarantees that this will represent the current object in scope, rather than window, a DOM element, or some other less predictable thing.

That’s what I’ve got for now. Does your mind hurt yet? When you recover, do you think you might use this approach in your apps? Let me know if in the comments below.

    • #backbone.js
    • #javascript
    • #MVP
    • #MOVE
    • #pub/sub
  • 9 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Async Template Loading With Backbone

This is my fifth post in a series on Backbone.js. Here are the first 4 in case you need to get caught up:

  1. Hey, check out my Backbone
  2. Aligning my Backbone
  3. Backbone Routers Are Configuration
  4. Grokking Backbone Views

In my previous post, I dug into the guts of how Backbone Views work, how to render them using client-side templating, and extending off of Backbone.View’s prototype. This post is going to build off of the previous one. Today, we’re going to talk about lazy-loading your client-side template HTML files asynchronously, caching, pre-compiling them, and why these are usually all good ideas. But before we get into the Why’s and How’s, I want to talk about the Why Not’s.

When async templates don’t make sense

I generally subscribe to Jeff Atwood’s idea that the best code is no code. Jeff probably didn’t originate that, but I’ve read it in several of his blog posts, and it has stuck with me throughout my career. So when does loading your templates asynchronously via AJAX, pre-compiling and caching them not make sense? When you really want to avoid unnecessary code. You can just as easily stick your templates inside inline <script> tags, hang them off of properties on your views, or pre-load them with an Asynchronous Module Definition (AMD) framework like Require.js.

Additionally, in the event that you’re writing an app that requires some sort of offline support, lazy loading anything from the server isn’t really an option. You really need certain features at your fingertips as soon as the page loads. I know that’s kind of a no-brainer, but it’s definitely worth mentioning.

So why would I use this then?

Because it’s faster! Lazy loading allows you to only load the templates that your application needs at any given time. This helps lighten the initial load of your application’s content. It also helps reduce the amount of HTTP requests initially sent back to the server as the page loads if they’re pre-loaded with something like Require.js.

You can also pre-compile your templates to optimize their performance when you lazy load them. While pre-compilation isn’t unique to this approach of template loading, it does give you a nice unified place to put this functionality.

Finally, this approach also give you a single place to manage initialization of any partials your app might need to care about. It allows you to encapsulate how you actually render your templates. You can use whatever templating library you like (Underscore, Mustache, Handlebars, etc). Now you can easily change this implementation in a single place, rather than sprinkling this concern throughout your views.

The Usage

In my last post, I showed some examples of how Backbone Views can render their content from a hard-coded string stuffed in a template property on the View object. You’ll also often see templates stored as HTML fragments inside <script type="text/html"> blocks that can be selected by ID from jQuery. Both of these are nice for quick and dirty implementations. However, I typically like to store my templates in separate HTML files located in a /templates folder just to keep things organized a little better.

Here’s what our usage would look like if we refactored the previous code example to use a TemplateManager object to lazy-load our templates for us.

FooView.js

var FooView = Backbone.View.extend({
    tagName: 'li',
    className: 'foo',

    // `template` is now the name of a file (sans extension) instead of the HTML 
    // fragment itself
    template: 'foo-list-item',
    events: {
        'click .fooButton': 'fooClicked'
    },
    initialize: function (options) {
        this.model = options.model;
        this.model.on('change', this.render);
        _.bindAll(this);
    },
    render: function () {
        var that = this;

        // Note that we're still doing much the same thing to create the HTML content
        // and stuff it into the DOM, but we're doing it inside this callback.
        TemplateManager.get(this.template, function (tmp) {
            var html = tmp(that.model.toJSON());
            that.$el.html(html);
        });

        // And we're still returning `this`, but it's highly likely that our `render`
        // method will return *before* the HTML has been placed into the DOM.
        return this;
    },
    fooClicked: function (e) {
        alert('ouch!');
        return false;
    },
});

Remember how I talked earlier about rendering templates asynchronously? Yep. That’s what’s happening here. Almost every time, our view.render() function will return before the HTML content is actually placed onto the page. You may ask, “How is this possible? Why would you do it that way”. The async nature of this approach certainly adds a bit more complexity, but it makes up for the added complexity in speed. Our app won’t block execution whilst waiting for that HTTP request to finish, and when the content has been loaded, we’ve provided a nice callback so our View knows what to do with it when it completes.

Let’s look at the implementation of a TemplateManager to see how this works.

The Implementation

If you’re a server-side coder, think of the TemplateManager as a sort of static class or object that just has a handful of utility methods or properties.

TemplateManager.js

var TemplateManager = {
    
    // Here, we're keeping an object literal around to act as a hash table, and we'll
    // be using it to cache each template that gets loaded from the server.
    templates: {},
    get: function (id, callback) {

        // Can we find this template in the cache?
        if (this.templates[id]) {

            // Yes? OK, lets call our callback function and return.
            return callback(templates[id]);
        }

        // Otherwise, lets load it up. We'll build our URL based on the ID passed in.
        var url = '/templates/' + id + '.html',

        // And use a handy jQuery library called Traffic Cop to handle marshalling 
        // requests to the server. This will prevent multiple concurrent requests 
        // for the same resource.
            promise = $.trafficCop(url),
            that = this;

        // Wire up a handler for this request via jQuery's promise API
        promise.done(function (template) {

            // `template` is a string of HTML loaded via `$.ajax`. So here, we 
            // can take the opportunity to pre-compile it for performance. When we 
            // pre-compile a template, it returns a function that we can store in our 
            // cache for future use.
            var tmp = Handlebars.compile(template);
            that.templates[id] = tmp;
            callback(tmp);
        });
    }
};

You probably noticed in the above code example my usage of $.trafficCop. It’s a super useful jQuery plugin that acts as a proxy for $.ajax. It comes in really handy when you have several concurrent requests coming in for the same resource. A great example of this would be rendering a list view. Let’s assume this list view might have a collection of child list item Views that require their templates to be loaded as well. TrafficCop would prevent more than one request from actually making it to the server. It stores the callbacks to each request for a resource and will call them back in the correct order.

I picked it from from Derek Bailey. Check out the repo on GitHub for more info on TrafficCop.

Handling Partials with TemplateManager

In addition to lazy-loading templates on the fly, I also will use TemplateManager to pre-load and register partials when our app is initialized.

var TemplateManager = {
    // ...

    // You could stash an array of well known partials that need to be rendered
    // and registered with your Templating engine of choice.
    partials: [
        { name: 'fooForm', template: 'foo-form' }
    ],
    registerPartials: function (callback) {
        var that = this;

        _.each(this.partials, function (partial, index) {

            // As we're iterating over our partials, we can call our
            // existing `get` function to pre-compile and cache them.
            that.get(partial.template, function (tmp) {
                Handlebars.registerPartial(partial.name, tmp);

                if (index + 1 === that.partials.length) {
                    callback();
                }
            });
        });
    }
};

Now when we’re bootstrapping our app, we can pre-load all of our partials before starting our router.

app.js

$(function () {
    TemplateManager.registerPartials(function () {
        var router = new FooRouter({ model: someData });
        Backbone.history.start();
    });
});

The benefit of this is a little bit more specific, but it enables you to call partials by name in your templates to encapsulate common HTML fragments.

new-foo.html

<div class="new-foo">
    <h3>Fill out the following form to create a new foo</h3>
    {{> fooForm}}
</div>

edit-foo.html

<div class="edit-foo">
    <h3>Editing foo: '{{name}}'</h3>
    {{> fooForm}}
</div>

That basically covers it. As you can probably tell from my examples, I’ve been using Handlebars quite a bit for my templating. So far I’m becoming a fan. It’s got a good balance of functionality via partials, blocks, helpers, etc. These help keep imperative code out of your template markup. And pre-compiling helps boost performance a lot (check out Derek Bailey’s blog post on this subject for more details).

It’s also worth mentioning that this technique is implemented in Derek Bailey’s Backbone.Marionette plugin. I haven’t had a chance to kick the tires on it yet, but I’ve heard great things about it.

So what do you guys think? Is the added speed and flexibility of async template loading worth it to you? Do you plan on using this technique in any of your single page apps?

    • #Backbone
    • #async
    • #handlebars
    • #javascript
  • 9 months ago
  • 1
  • Comments
  • Permalink
  • Share
    Tweet

Grokking Backbone Views

This is my fourth post in my series on Backbone.js. Make sure to read the first three if you haven’t had a chance to check them out yet.

  1. Hey, check out my Backbone
  2. Aligning my Backbone
  3. Backbone Routers Are Configuration

In my last post, I started digging into the guts of how Backbone Routers work. In this post we’re going to dive into Backbone Views. In Backbone, Views take a more active role than you may be used to if you’ve been working with frameworks like Rails or ASP.NET MVC. On the server, Views are generally logic-lite templates. They’re typically HTML markup fragments with a smattering of code blocks to handle anything that needs to be dynamic.

Backbone Views, however, are all code (though mostly configuration) and contain any necessary logic for the View to render itself in the DOM and wire up any event handlers it needs to worry about. In Backbone, Views are, in many ways, like Controllers (far more than Routers are). Views serve as your app’s entry point for user interaction and will be responsible for kicking off events that your apps will use to actually get things done. Backbone Views serve as a window into your Model’s state for the user.

The basics

Lets start with an example of a basic View, annotated with comments of course…

var FooView = Backbone.View.extend({

    // `tagName` and `className` are standard parts of Backbone.View that
    // are used to dynamically create the view's `el` property.
    tagName: 'li',
    className: 'foo',

    // `template` is an HTML fragment that will be populated with data
    // from the model. More on this further on in the post.
    template: '<strong><%= name %></strong><a href="#" class="fooButton">Click me</a>',

    // `events` functions as a hash table of events and function names
    // for a Backbone.View to map DOM events to. Think of it as the Router's
    // `routes` hash table for your View.
    events: {
        'click .fooButton': 'fooClicked'
    },

    // `initialize` is used as an entry point into the View. It functions
    // like a constructor.
    initialize: function (options) {

        // If your view needs to be dynamic, you'll want to pass it a model.
        this.model = options.model;

        // Here, we're listening to the `change` event on the model. Any time
        // the Model this View is watching changes, its `render` method will
        // get called, allowing the view to keep up to date with the Model state.
        this.model.on('change', this.render);
    },

    // `render` dictates how the Model will be represented in the DOM. You can use
    // whatever methods you like to create your View's content. The most popular
    // way of doing so is to use a client-side templating system.
    render: function () {

        // Creating an HTML string populated with the Model our view is watching.
        // Here, we're using Underscore's built in `template` function, but you
        // can use any other templating system, or concatenate strings manually
        // if that's your thing.
        var html = _.template(this.template, this.model.toJSON());

        // Inject the HTML fragment into our view's `$el` alias (more on this)
        // below...
        this.$el.html(html);

        // It's always good practice to return `this` from your render method
        // so it can be chained off of.
        return this;
    },

    // Here's our click handler. If you're using jQuery, this will be a 
    // jQuery click event.
    fooClicked: function (e) {
        alert('ouch!');
        return false;
    },
});

So with the implementation now in context, let’s take another look at how you would use this view. Remember, we’re only going to be directly dealing with Views from within our Presenter. For posterity, I’ll also include a basic implementation of some of the other parts so you can see how things work together.

/**
 * Setting up a very basic Model and Collection structure here...
 */
var Foo = Backbone.Model.extend({}),
    FooCollection = Backbone.Collection.extend({
        model: Foo
    });

/** 
 * Here's our presenter. Just much like the one in my second post...
 */
var FooPresenter = function (options) {
    this.fooCollection = options.model; 
};

FooPresenter.prototype.showView = function (view) {
    if (this.currentView) {
        // Note that we're calling `close` here. This method does not exist in 
        //Backbone.View yet. I'll demonstrate how to add this extension method 
        // and why it's important further along in this post.
        this.currentView.close();
    }

    this.currentView = view;

    // Note the chaining when passing the view's `$el` to jQuery
    $('#container').html(this.currentView.render().$el);
};

FooPresenter.prototype.showFoo = function (id) {
    var view = new FooView({ model: this.fooCollection.get(id) })
    this.showView(view);
};

/**
 * Our super basic Router.
 */
var FooRouter = Backbone.Router.extend({
    routes: {
        'foos/:id': 'showFoo'
    },
    initialize: function (options) {
        this.presenter = new FooPresenter(options);
    },
    showFoo: function (id) {
        this.presenter.showFoo(id);
    }
});

/** 
 * Here's our app's entry point inside a jQuery "document ready" handler
 */
$(function () {
    // Setting up some dummy data...
    var fooCollection = new FooCollection([
            new Foo({ id: 1, name: 'foo1' }),
            new Foo({ id: 2, name: 'foo2' })
        ]),
        router = new FooRouter({ model: fooCollection });
    Backbone.history.start();
});

What’s the deal with el and $el?

The el property is the DOM element that the View is watching. Think of el as the representation of your View in the DOM. Every Backbone View has one, whether it’s been inserted into the DOM yet or not. If the HTML element your View is supposed to know about is already on the page, you can define it explicitly using a CSS selector. The $el property is a jQuery (or Zepto) alias of el that gets created when the View is initialized. So assuming you have an HTML fragment that looks like this:

<div class="wrapper">
    <section id="foo-container"></section>
</div>

You could have a Backbone View that’s defined like this:

var FooView = Backbone.View.extend({
    el: '#foo-container',
    // ...
});

The thing to remember is that generally, you’ll want to do this when the element your View is concerned with is already present on the page. For example, if you’re rendering all of your HTML on the server, or if you’re trying to fit Backbone into a legacy application for a more modern twist to your UI code. If you don’t define el explicitly, Backbone will create it for you based on the tagName, className and id properties you configure.

If you are rendering your HTML on the fly, or fetching it from the server via AJAX later on, Backbone’s View implementation will create el for you in memory if it’s not present in the DOM. This is my preferred method of doing things, especially if I’m using a templating system in conjunction with my Views. I like to keep things as tidy as possible. So I usually like to create and remove DOM elements on the fly rather than taking the hide/show approach of toggling views.

Rendering Templates

In Backbone, you can use any templating method you want to populate your View’s el. I’ve used the basic templating system that comes baked into Underscore.js as well as Mustache and Handlebars. So far, Handlebars is my favorite. The syntax is super simple (much like Mustache’s), but offers a little bit more utility than Mustache alone does.

The nice thing about this approach is that you can use any means necessary to populate your View’s el container with content. If you really love concatenating strings together, knock yourself out.

How does the eventing system work?

Backbone uses a well-known hash table called events on the View. It works in much the same way that routes works on the Router. When your View is initialized, Backbone will iterate through each member of that hash table and create an event handler for it. It uses this pattern:

events: {
    'eventName selector': 'methodName'
}

On the left side of each item in the hash, Backbone will parse out the DOM event name and the CSS selector of the element it’s delegating to. On the right hand side of the hash is the name of the View’s method that will handle the event. If you’re using jQuery, Backbone will use jQuery’s delegate and undelegate functions to set up and tear down these events. Additionally, Backbone’s View system implements two methods called delegateEvents and undelegateEvents to provide additional utility, should you ever need it.

Extending Backbone.View

Have you ever used a web app that uses a lot of JavaScript, and it just feels sluggish? Me too. It’s no fault of JavaScript’s that the app reacts slowly. The fault lies squarely on the shoulders of the developer. Odds are, when you run into something like this, it’s because the developer is not doing a very good job of managing memory.

To be clear, JavaScript is not an unmanaged language. It has a garbage collector. When the runtime isn’t using an object, it gets eaten just like you might expect in any other managed language. The main ‘gotcha’ happens when you have objects loaded into memory that are associated with DOM elements. To illustrate, if you have a large array that gets created in an event handler, and say that event goes out of scope once it completes, there’s no guarantee that the array will be eaten by the garbage collector right away, because the DOM element still exists on the page. This is quite a bit more prevalent in certain browsers (cough IE cough) than it is in other, more modern browsers.

These issues most likely won’t ruin your app. I’m sure we’ve all written enough nasty looking spaghetti-code JS apps to prove that it’s not the end of the world if you’ve been guilty of this sort of thing in the past. However, it is nice to know it exists and that Backbone provides a nice way of cleaning up after yourself. It wasn’t until I began writing larger scale JavaScript applications that I realized I needed to start worrying about memory management.

Remember that line of code in the FooPresenter implementation of showView above, where I called this.currentView.close()? Backbone’s View implementation does not have a close method. So here’s how I implemented it (which I’m pretty sure I got from Derek Bailey’s blog):

Backbone.View.prototype.close = function () {

    // A View's `remove` method will call `$el.remove()` to remove the View's element
    // from the DOM.
    this.remove();

    // Calling `unbind` here will unbind any DOM events that the View's `el` element 
    // or any of its children were listening for
    this.unbind();

    // I also do a little check here to see if the current View has defined an `onClose`
    // method. If so, I will call it.
    if (typeof this.onClose === 'function') {
        this.onClose();
    }
};

Here’s what a View’s onClose implementation might look like:

var FooView = Backbone.View.extend({
    onClose: function () {
        // In `close`, you can unbind any events you listened for in `initialize`
        this.model.off('change');

        // Additionally, if your View has any child Views that it created at any point,
        // you can iterate over them and call `close` on each child View.
        _.each(this.childViews, function (view) {
            view.close();
        });
    }
    // ...
});

So that provides a way of keeping your memory footprint nice and small whilst helping keep the DOM free of clutter, and it does so in a way that you can use across any Backbone View. I find myself adding this to almost every Backbone project that I work on.

I hope this post helped you grok Backbone’s View system more fully. If you have any questions or advice, please feel free to leave me a comment!

    • #javascript
    • #backbone.js
    • #underscore.js
    • #handlebars
    • #mustache
  • 10 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Backbone Routers Are Configuration

This is the third post in my series on Backbone.js Make sure to catch up on the first two if you haven’t already.

  1. Hey, check out my Backbone
  2. Aligning my Backbone

In my last post I covered how using the Model View Presenter design pattern will help you write cleaner apps without cluttering your Routers with unnecessary application or presentation logic. In this post, I’m going to get into the guts of the Backbone Router object, demonstrate how I’ve used it, and hopefully dispel some misunderstandings about its use.

Routers are really just configuration files

When we look at other MVC-like frameworks (especially on the server side), they all use a router to control how incoming URLs get mapped to the appropriate controller action method. Backbone.js is no different in that respect.

Let’s consider a couple examples from Backbone’s server-side cousins. In ASP.NET MVC, you set up your route tables in Global.asax.cs:

public class FooApplication : MvcApplication
{
    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }

    public static void RegisterRoutes(RouteTable routes)
    {
        // In ASP.NET, you have to define routes explicitly via routing table 
        // definitons. These work similarly to how Backbone does things.
        routes.MapRoute(
            "Foos",
            "foos/{action}/{id}",
            new { controller = "Foo", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

Or in Rails, your routes.rb file probably looks something like this:

FooApp::Application.routes.draw do
  
  # In Rails, however, you can define a `resource` via a model symbol name and 
  # the framework just knows how to map RESTful URLs to it.
  resources :foos

  # You can also define individual URLs and map them manually.
  match '/about' => 'pages#about'  
  root :to => 'pages#home'

end

When we consider these two popular frameworks and how they treat their respective routing systems, we can draw the same conclusion about both of them. Routers are configuration. Yes, they’re code files and not XML, Yaml, JSON or some other structured data file, but actual imperative code. However, any sane developer would never put any sort of business logic in these files, right? Right?

So if the established use pattern for routers in an MV* framework is to treat them as configuration files, then why treat Backbone Routers in any other way?

Not to sound all soap-boxy, but here’s how I’ve been setting up my Routers in Backbone (with comments to hopefully help explain the important bits).

// Here's our Router "class" definition. There are a few things we need to wire up
// before it's ready for action...
var Router = Backbone.Router.extend({

    // `initialize` is a standard part of every Backbone construct. It behaves 
    // kind of like a constructor that accepts an object called `options`.
    initialize: function (options) {

        // Since I often use a presenter, I will instantiate it here and delegate 
        // all application logic to it. Note that we're passing the options object 
        // strait through to the Presenter.
        this.presenter = new Presenter(options);
    },

    // This is our route table. In this JSON object, we can define any URL we
    // want to handle on the left side of the ':', and on the right side, we
    // list the name of the method that will handle that URL.
    routes: {
        '': 'index',            // Empty string will represent "home"
        'about': 'about',
        'foos': 'listFoos',
        'foos/:id': 'showFoo',  // Note the 'id' URL param used here
        '*options': 'notFound'  // `*options` is a catchall route in Backbone
    },

    // Here's our handler for our home page. So if our website's address is 
    // `http://foo.com`, a route with an empty string would catch the root
    // URL of the site. 
    index: function () {
        this.presenter.showHomePage();
    },

    // Handler for the `http://foos.com/foos` URL
    listFoos: function () {
        this.presenter.showFooList();
    },

    // Here's the handler for `http://foos.com/foos/:id`. Notice that the URL parameter 
    // `id` is mapped below as a function argument.
    showFoo: function (id) {
        this.presenter.showFoo(id);
    },

    // The `*options` catchall route is a well known value in Backbone's Routing
    // internals that represents any route that's not listed before it. It should to
    // be defined last if desired. We'll just have the presenter render a 404-style
    // error view.
    notFound: function () {
        this.presenter.showPageNotFound();
    }
});

// To actually use our router, we'll just "new it up" and pass in any options necessary.
// Let's pretend we already have a model populated with data that we're passing to it.
var router = new Router({ model: foos });

// Now that we have a router object loaded in memory, we can start recording URL 
// history. Backbone.history worries about watching the URL and calling the appropriate 
// functions listed in the router's `routes` object. Here we're going to use HTML5
// PushState, so that we can generate cleaner looking URLs rather than hash-based ones.
Backbone.history.start({ pushState: true });

Hopefully that helps demystify Backbone’s routing system for those unfamiliar with how it works. When you really break it down to its most important bits, the Backbone.Router construct really is just fancy looking configuration. Think this’ll help you write cleaner code? Let me know in the comments.

    • #Backbone
    • #java
    • #mvp
    • #routing
  • 10 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Aligning My Backbone

This is part 2 in my blog series on Backbone.js. Make sure to check out the first post if you haven’t read it already.

In my last post I covered the basics on each part of Backbone and provided a very basic intro. Just to reiterate, Backbone.js is a MV* framework for writing complex single-page JavaScript apps. It’s just plain ol’ JavaScript and is very un-opinionated. These design choices make Backbone very flexible and incredibly powerful. My focus in this post will be why adding a bit of your own flavor, patterns and opinions can be highly productive.

Model View Presenter

While building lots of Backbone apps over the past 9 months or so, I’ve gotten cozy with the MVP design pattern. In MVP, the notion of a Controller is replaced by that of a Presenter. A Presenter behaves like a super-Controller. It not only concerns itself with acting as a proxy for the Model, it actually has some say over injecting the Views into the DOM and managing their lifecycle. 

But… But… But… Backbone doesn’t have a Presenter!  How could you possibly use MVP in a Backbone app?

It took me a little while to wrap my head around this. So don’t feel bad if you find yourself asking this very same question. I’ve asked it, and I’m sure many others have too. You can create your own Presenter object. Not every piece of a Backbone app has to be a Backbone construct. Let that sink in. Once you understand that you’re just writing JavaScript, it’s incredibly liberating.

OK fine. Enough talking. Show me some code!

At first glance you’ll note that most of my code looks like the standard stuff you’ll see in a Backbone app. The main differences will be seen in the Router and the Presenter itself.

Here’s what the router would look like…

    var FooRouter = Backbone.Router.extend({
        routes: {
            'foos': 'listFoos',
            'foos/:id': 'getFoo'
        },
        initialize: function (options) {
            // Pass options through to the Presenter
            this.presenter = new FooPresenter(options);
            _.bindAll(this);
        },
        listFoos: function () {
            this.presenter.listFoos();
        },
        getFoo: function (id) {
            this.presenter.getFoo(id);
        }
    });

No too shabby, eh? We’re just passing everything through from the Router to the Presenter. Keeps the router nice and lean. It removes unnecessary logic and lets the Router focus on… um… routing!

And here’s how the Presenter might look…

    var FooPresenter = function (options) {
        // Let's pretend that we've already got a list of Foos
        // hydrated from the server.
        this.foos = options.model;
        _.bindAll(this);
    };
    
    FooPresenter.prototype.showView = function (view) {
        if (this.currentView) {
            // I often create a 'close' method off of Backbone.View
            // to help Views clean up after themselves and to
            // prevent memory leaks. I'll get into this in a future
            // post on Views.
            this.currentView.close();
        }
        this.currentView = view;
        $('#some-container').html(this.currentView.render().$el);
    };
    
    FooPresenter.prototype.listFoos = function () {
        var view = new FooListView({ model: this.foos });
        this.showView(view);
    };
    
    FooPresenter.prototype.getFoo = function (id) {
        var foo = this.foos.get(id),
            view = new FooView({ model: foo });
        this.showView(view);
    };

That’s pretty much all there is to it. If you’re familiar with how “classy” objects get created in JavaScript and how the prototype chain works, you’re in good shape. And just like with MVC Controllers, you want to keep your Presenter methods nice and lean as well. Nothing super complicated going on here.

Remember, adding patterns you’re already familiar with will help you become a better JS developer and will help you design little programs that you can compose into large, testable systems.

In my next post, I’ll cover how to manage messaging between the various components of your app to keep things nicely decoupled.

    • #javascript
    • #backbone.js
    • #MVP
  • 11 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Hey, check out my Backbone

Backbone.js

This is the first post in what will become a series of posts covering Backbone.js. I’ve been developing Backbone apps pretty heavily lately and have learned a lot. This series will serve to document what I’ve learned for personal purposes, and hopefully will be helpful for developers looking to learn more about it.

What’s a Backbone.js?

Backbone.js is a JavaScript framework. Lots of people like to use it to build larger scale applications that run in a web browser, completely decoupled from their server framework of choice. It’s an incredibly powerful tool to have at your disposal. There’s so much information and buzz out there about this framework, though, that I think it may be best to start off describing what Backbone isn’t.

Huh?

You’ll often hear Backbone referred to as a client side MVC framework, like Rails or ASP.NET MVC. I disagree with this comparison. While its useful to provide context for what Backbone can do, it leads down a very confusing path where many incorrect assumptions get made.

These bad assumptions often get made because of an unfortunate naming choice early on in the framework’s development. In previous versions, the Backbone Router was actually called “Controller”. Thankfully, right around the 0.5.3 release, Jeremy Ashkenas and team decided to rename “Controller” to  reflect its actual purpose: a Router.

Confusing naming conventions aside, I like to call Backbone an MV* framework, where the * is basically a wild card (you could go with MVC, MVP or MVVM). Backbone has Models and Views. It does not, however, come with a baked in Controller (in its most current form). Because of the unfortunate naming mishap in earlier versions, many demos you’ll run into out on the web will treat the Router as if it were a Controller. While this works from a technical standpoint, and is often the simplest implementation, I’ve found that it tends to lead toward a more limited understanding of the framework. I’ll get into more detail on that later on in this series.

I’m not going to go super in depth about each individual part of Backbone just yet, but here’s the 10k foot overview:

Models

Like in most MV* implementations, in Backbone, models represent your data. They also have a lot of nice utility methods to handle data transport. You can tell a model where it lives on the server by passing it a RESTful URL root. And should you ever call ‘save()’ on that model, it will know how to persist itself. And, of course, you’ll want to place much of your domain-specific business logic in these model objects.

Collections

Backbone collections are basically lists of models. The really nice thing about the way they’re implemented. Thanks to Underscore, it’s really easy to query, slice and dice your data on the client.

Underscore.js is a dependency of Backbone and is super useful in its own right.  Underscore provides lots of nice utility functions that Backbone hooks into. Underscore is to plain ol’ JS as jQuery is to the DOM.

Views

Views are the representation of your UI reflected as code. You get a lot of flexibility in how you choose to implement them, though. They can already exist on the page (rendered by the server), or you can populate templates (HTML fragments) with data from your models and have the view render them on the page.

Views can listen for DOM events via jQuery or Zepto (whichever you happen to be using). This often makes Views feel a bit like Controllers in that they are often the entry point for user interaction in your app.

Routers

As I mentioned earlier, a lot of people make the mistake of thinking of the Backbone Router as a Controller, simply because it handles incoming URLs in a similar fashion that server-side MVC developers are often familiar with. In an upcoming post, I’ll be diving into the pattern I use to avoid falling into this trap.

Events

Internally, Backbone uses an object based event binding system to enable a really elegant publish/subscribe implementation. You can use this feature to listen for events fired by models and collections. You can also extend this functionality to create your own event aggregator for your app, allowing different constructs or modules to talk to each other without unnecessary dependencies.

History

Backbone’s implementation of browser history is where a lot of the magic happens. It watches the URL hash, or listens to PushState (if your app uses it, and the browser supports it), and will send the URL changes to your router to handle. This is really nice in that you can add bookmarkability into your single page JavaScript applications for free.

Wrapping up

Individually, these pieces aren’t super special, but as a package, they become really powerful. It’s also important to note that Backbone plays really nicely with other JS libraries, so it’s very easy to mix and match things to create your own stack.

In my next post, I’ll be digging into the MVP (Model View Presenter) pattern that I use to build apps, and why adding a bit of your own opinions into Backbone can be really important and highly beneficial.

    • #backbone.js
    • #underscore.js
    • #javascript
  • 11 months ago
  • Comments
  • Permalink
  • Share
    Tweet

Musings on asynchronous programming in JavaScript

I had a brief discussion today with my buddy Nick and something he said struck me. And it may come across that I’m trying to pick on him in my post. But our little chat really got me thinking, as they often do (which makes Nick such an awesome guy to code with). So I thought I’d share…

 I’ll try to paraphrase Nick’s statement as best I can. Here’s the gist of what he said regarding writing large-scale, asynchronous applications in JavaScript (Backbone.js in this case):

This technique of coding adds a completely different level of complexity. It’s not going to catch on until it gets easier for developers to work with.

I agree with Nick’s first thought. Asynchronous programming is a whole new ball game. It’ll melt your brain in ways you never conceived your brain of ever being melted before.

… However …

Async programming is still fairly new. It wasn’t born yesterday, but it’s new in the sense that it’s just now getting it’s time in the spotlight thanks to projects like Node.js, jQuery, and Backbone.js. It’s new to a lot of us who have been stuck in the synchronous world for the past few decades.

I disagree that async development (particularly using JavaScript in large scale applications) will have to get “easier” to be widely successful. I think it’s going to require a different mindset of people who choose to work in that space.

Asynchronous code is definitely not “the path of least resistance”. It’s a different animal altogether. It’s a complete paradigm shift, not unlike what the development community went though when hackers writing imperative code had to really sit down and grok Object Oriented Programming. I would also say that its probably not for everybody, and certainly not suitable for every project.

I think for developers to be successful in writing asynchronous code, they need to stretch themselves a bit to wrap their minds around it and invest the time necessary to do it right. I’m sure there will be more and more libraries that come out that attempt to reduce the “callback hell” that comes with the territory, but the fundamental building blocks used will remain the same (closures via callbacks, promises, etc).

It’s awesome to see it maturing at such a staggering rate. This stuff makes it a fantastic time to be a developer.

    • #JavaScript
    • #async
  • 1 year ago
  • Comments
  • Permalink
  • Share
    Tweet

Steve Jobs - by Walter Isaacson

I’m normally not one to write book reviews. If it’s not directly related to design or code, I usually dont bother posting about it. I suppose I can make an exception just this once.

I just finished reading the biography on the life and career of Steve Jobs by Walter Isaacson. It was brilliant. All I can really say is “Wow”. I’ve got a newfound appreciation for who he was as a person, his genius and his accomplishments.

I saw a lot about his personality to disagree with, but I found that I resonated with his tastes and character far more than I expected, and I picked up a bunch of valuable takeaways from his experience. If you build or create anything in your career, whatever that may be, and you actually care about what you’re creating, you really ought to read this book.

    • #Steve Jobs
  • 1 year ago
  • Comments
  • Permalink
  • Share
    Tweet

More than just a house

This past Saturday night my wife, Rebecca, and I went to 1Mission’s 2012 Gala and it was awesome. The guys that run that charity never cease to amaze me with the innovative things they do.  This weekend, I got my bell rung pretty good.

I’m no stranger to their cause. They build houses for the impoverished people living in the barrios of Puerto Penasco, Mexico. But I think that description of their mission is highly misleading and undermines what it is that they actually do. 1Mission is empowering these people to fix their own circumstances. 1Mission doesn’t do traditional aid-type charity work. They partner with the locals by educating them, giving them a sense of ownership over their situation, thereby giving them a means to pull themselves out of it.

The video below is a great illustration of what they actually do…

1Mission has a unique take on the problem of poverty, and behind that perspective, they’ve created a very effective process. It’s working wonders in their Penasco community. So much so, that other organizations around the globe are asking to partner with 1Mission so they can learn the process.

It’s because of Jason Law, the founder of 1Mission, and his team’s vision that I even began my work on Grassroots. It’s an honor for me to be able to name some of these guys as friends and I consider myself to be super lucky to be involved, even in a small way, in what they’re doing. I’m blessed to be able to partner with guys like this that “get it” when it comes to building Open Source Software that can have a profound impact on the people around them.

OK, enough mushy stuff. I’ll leave you with one last video from the Gala this weekend. Hope you enjoy! Back to hacking!

Source: 1mission.org

    • #1Mission
    • #207Miles
    • #Grassroots
  • 1 year ago
  • 1
  • Comments
  • Permalink
  • Share
    Tweet
← Newer • Older →
Page 1 of 4

About

Avatar Random thoughts by a software craftsman & design nerd.

Pages

  • About Json
  • Backbone.js

json.elsewhere

  • jasonoffutt on Dribbble
  • jasonoffutt on Behance
  • JasonOffutt on Forrst
  • @JasonOffutt on Twitter
  • JasonOffutt on Foursquare
  • JasonOffutt on github

Latest Tweets

loading tweets…

Following

My favs

  • Post via izs
    Beliefs

    Don’t believe everything you hear. You will by default. It takes a lot of effort to un-believe it once you hear it.

    Don’t believe...

    Post via izs
  • Post via izs
    On ES 6 Modules

    A few things have rubbed me the wrong way about the current Modules and Module Loader specification. I regret that I have not been...

    Post via izs
  • Post via penderworth
    What's wrong with Android

    image

    In the recent months, I have spent a lot of time using an HTC ThunderBolt after selling my iPhone 4 because AT&T’s...

    Post via penderworth
See more →
  • RSS
  • Random
  • Archive
  • Ask me anything
  • Mobile

Effector Theme by Carlo Franco.

Powered by Tumblr