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