Client-side MVC: Backbone.js

Backbone.js

Your template is in my Javascript

Mike Estes

Web Developer

Backbone.js

Don't they make TVs?

MVC?

Model

View

Controller

Backbone.js "MVC"

Models

Views

Containers...

But Really

Model

Models
Collections

View
templates
  • _
  • mustache
  • ???

Controller

Views

Confused yet?

Backbone Models

Define our model

var Client = Backbone.Model.extend({
  fullname: function() {
    return this.get('firstname') + ' ' + this.get('lastname');
  }
});

Create our first client

var client1 = new Client({
  firstname: "Jane",
  lastname: "Customer",
  email: "jane@example.com",
  bill: 75.00,
  state: "WA"
});

Backbone Models

Change some data

client1.set("email", "jane2@example.com");
client1.save();

Collections

var Clients = Backbone.Collection.extend({
  model: Client,
  url: "/api/clients"
});

Backbone Collections

Data filtering

var Clients = Backbone.Collection.extend({
  model: Client,
  url: "/api/clients",

  unpaid: function() {
    return this.filter(function(client) { return client.get('balance') > 0; });
  }

  outOfState: function() {
    return this.filter(function(client) { return client.get('state') != "WA"; });
  }

});

Backbone Views



  addAll: function() {
    this.clients.each(this.addOne);
  },

  addNewClient: function() {
    this.clients.create({
      name: this.$("input.name").val(),
      bill: this.$("input.bill").val(),
      state: this.$("input.state").val(),
    });
  }

});

var ClientListing = Backbone.View.extend({
  tagName: "div",
  events: {
    "submit form":        "addNewClient"
  },

  initialize: function() {
    this.clients = new Clients();

    this.clients.bind('add',     this.addOne);
    this.clients.bind('reset',   this.addAll);
  },

  addOne: function(item) {
    var view = new ClientRow(item);
    this.$el.append( view.render() );
  },

Backbone Views


  updateClient: function() {
    this.model.set("name", this.$('input.name').val());
    this.model.save();
  },

  clear: function() {
    this.model.destroy();
  }

});
var ClientRow = Backbone.View.extend({
  tagName: "li",
  className: "client-row",
  template: Mustaches['client_row'],

  events: {
    "keypress input":       "updateClient",
    "click .button.delete": "clear"
  },

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

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

Frontend Templates: Mustache

Listing Template

<div id="user-info">
  Signed in as  (<a href="#" class="log-out">Log out</a>)
</div>

<div id="newClientForm">
  <input id="new-client" placeholder="Add a client..." type="text" />
  <input id="new-bill" placeholder="$..." type="text" />
  <input id="new-state" placeholder="State..." type="text" />
</div>

<ul id="client-list">
  <img src='images/spinner.gif' class='spinner' />
</ul>

Frontend Templates: Mustache

Row Template

<li class="{{#local}}local{{/local}}">

  <div class="view">
    <input class="edit edit-name" value="{{ name }}">
    <input class="edit edit-bill" value="{{ bill }}">
    <input class="edit edit-state" value="{{ state }}">
    <button class="client-destroy"></button>
  </div>

</li>

Frontend Templates: Underscore

Example Template

<script type="text/template" id="item-template">
<li class="<%= done ? 'completed' : '' %>">
    <div class="view">
        <input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %>>
        <label class="todo-content"><%= content %></label>
        <button class="todo-destroy"></button>
    </div>
    <input class="edit" value="<%= content %>">
</li>
</script>

Demo

Parse application for managing clients

Parse.com

Clients App