Anatomy of a SPA:
Client-side MVC

SPA: Single Page Application
MVC: Model-View-Controller

¡Hola!

I come in Peace

About this talk

Askani.net

  • A django models generator.
  • The biggest SPA I've made.
  • Which is not huge, but somewhat complex.
  • Fork it!

MVC...? Why?

But in the browser? How?

JavaScript?
That's not even a real language!

Lord forgive them,
for they know not what they say

JavaScript

It's evolution, baby

It's evolution, baby

The MVC pattern.

A metaphor to better understand it.

The MVC pattern is like cookies. Sort of.
Alvaro Mouriño

The cookie pattern!

Models

Models

  • Organizes the business data.
  • Is an abstract representation of the actors in the system.
  • Represents behaviour and communication.

Views

Views

  • Defines how the information will be presented.
  • The same information can have many looks.
  • Or even be displayed using different media.

Controllers

Controllers

So... Backbone?

Backbone.js

Models

Models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it.
Backbone.js website

Models

// You extend Backbone.Model with your domain-specific methods,
// and Model provides a basic set of functionality for managing
// changes.
var Cookie = Backbone.Model.extend({

    defaults: {
        'flavour': 'N/A',
        'hasChips': false
    },

    getFlavour: function() {
        return this.get('flavour');
    }

});

// Simple... huh?

Inheritance

// Extends from Cookie and sets some properties.
var ChocolateCookie = Cookie.extend({

    // If you define an initialize() function, it will be
    // invoked when the model is created.
    initialize: function() {
        this.set({
            'flavour': 'chocolate'
        });
    },

    // Overriding the set method.
    set: function (attributes, options) {

        // Do something interesting

        // Invoking the parent object's implementation of the
        // overriden method.
        Cookie.prototype.create.call(this, attributes, options);
    }

});

Using models

// Default parameters.
var myCookie = new ChocolateCookie({
    'hasChips': false
});

myCookie.get('flavour');
// -> 'chocolate'

// This cookie has chips.
myCookie.set({
    'hasChips': true
});

// Triggers a 'destroy' event and performs the DELETE action on the
// storage backend.
myCookie.destroy();

// Check all the available methods on the doc (A.K.A. RTFM)

Views

Backbone views are almost more convention than they are code — they don't determine anything about your HTML or CSS for you, and can be used with any JavaScript templating library.
Backbone.js website

Views

var CookieView = Backbone.View.extend({

    tagName: "div",
    className: "cookie",
    template: _.template($('#cookietemplate').html()),

    events: {
        "click .cookie":        "pickCookie"
    },

    initialize: function() {
        this.model.bind('change', this.render, this);
    },

    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }

});

Using views

var myCookie = new ChocolateCookie,

var view = CookieInAJarView({
    'model': myCookie
});

// Render a cookie in a jar.
view.render();


var view = CookieOnAPlateView({
    'model': myCookie
});

// Now render a cookie on a plate.
// Exactly the same, only changes the View object.
view.render();

The jQuery/Zepto dependency

Collections

Collections are ordered sets of models. You can bind events to be notified when any model in the collection has been modified and fetch the collection from the server.
Backbone.js website

Collections

var ChocolateCookieList = Backbone.Collection.extend({

    model: ChocolateCookie,

    localStorage: new Store('cookies'),

    initialize: function() {
        // Constructor
    }

});

Using collections

var cookies = new ChocolateCookieList([cookie1, cookie2, cookie3]);

// Get the cookies stored in the backend.
cookies.fetch();

// Get the first inserted cookie.
var first = cookies.at(0);

newCookie = new Cookie({
    'flavour': 'pajarito'
});
// Triggers an 'add' event and persists the object.
cookies.add(newCookie);
All glory to the Hypnotoad!

Sync (A.K.A. Storage)

Backbone.sync is the function that Backbone calls every time it attempts to read or save a model to the server.
Backbone.js website

Sync (A.K.A. Storage)
(cont.)

By default, it uses (jQuery/Zepto).ajax to make a RESTful JSON request. You can override it in order to use a different persistence strategy.
Backbone.js website

Persistence strategies

RESTful JSON

LocalStorage

How to use it?

<script type="text/javascript" src="js/backbone.js"></script>
<script type="text/javascript" src="js/backbone-localstorage.js">
</script>
var ChocolateCookieList = Backbone.Collection.extend({

    ...

    localStorage: new Store('cookies'),

    ...

});

Putting it all to work

 +-----------+           +---------+         +--------+
 |           |   Save()  |         |   Uses  |        |
 |  Storage  | <-------- |  Model  | <------ |  View  |
 |           |           |         |         |        |
 +-----------+           +---------+         +--------+
                              ^                  ^
                              | Has many         |
                              |                  |
                      +--------------+           |
                      |              |           |
                      |  Collection  |           |
                      |              |           |
                      +--------------+           |
                              ^                  |
                              |                  |
                              |                  |
   +--------------------------------------------------+
   |                 Your application                 |
   +--------------------------------------------------+

But wait, there's more!

Other backbones: Alternatives

Alternatives

My recommendation

Micro vs. full

To MVC or not to MVC

When not to use MVC

Thanks for listening

Questions?

Thank you!

  • Github: tooxie
  • @tuxie_
  • alvaro@mourino.net