Backbone 101



teaching-materials.org/backbone/



  • An open-source JS library
  • Helps organize JS for large web apps
  • Uses object-oriented principles for models and views

Backbone Pre-reqs


  • Object-oriented JS
  • Using a library
  • jQuery


...which we'll review!

Backbone Topics


  • Models
  • Views
  • Templating
  • CRUD Backend


...and we'll have exercises for each!

Review!

Object-oriented JS

Object-oriented JS

// The object "constructor"
var Product = function(config) {
  // The object "properties"
  this.name = config.name;
  this.type = config.type;
  this.inventory = config.inventory || 0;
};

// An object "method"
Product.prototype.buy = function() {
  this.inventory--;
  console.log("We now have " + this.inventory + " of " + this.name);
};

// Instantiating a new object
var product = new Product({
  name: "BetaBrand Disco FannyPack",
  type: "Accessory",
  inventory: 20
});

// Calling a method on a new object
product.buy();

Object-oriented JS

var Shirt = function(config) {
  // Re-using the Product constructor
  Product.call(this, config);
  this.colors = config.colors;
}
// Inheriting the Product methods
Shirt.prototype = Object.create(Product.prototype);

// Defining a new method on this object
Shirt.prototype.addColor = function(color) {
  this.colors.push(color);
  console.log("We now stock " + color);
};

// Instantiating a new object
var shirt = new Shirt({
  name: "Three Wolves Shirt",
  type: "T-Shirt",
  inventory: 33,
  colors: ["black"]
});

shirt.buy();
shirt.addColor("teal");

Using a library


  • Include a script tag to the library on your page
  • Call functions from that library

<script src="http://imagine-it.org/math.js"></script>
<script>
    var answer = math.sum(2, 2);
    alert(answer);
</script>

jQuery


// Finding elements
var code = $('code.javascript');
// Reading elements
alert(code.text());
// Changing elements
code.css('background-color', 'pink');
// Creating elements
var newCode = $('<code>// Whee!</code>');
$('#jquery-review').append(newCode);

BackboneJS

Models

What is a model?


Defining a model


You can define a basic Backbone Model with .extend()

var Product = Backbone.Model.extend();

You can also pass in an object for more configuration...

Setting defaults


var Product = Backbone.Model.extend({
  defaults: {
    name: "California",
    type: "T-shirt",
    colors: ["light gray"],
    tagline: "Cali says relax",
    newProduct: true,
    inventory: 28
  }
});

Note that an object literal is being passed into .extend()


Consider: Where else have we seen objects as arguments?

Instantiating new models


Create an empty model that inherits all the defaults

var shirt = new Product();

You can also override the defaults with an object

var shirt = new Product({
  name: "Roma",
  colors: ["green", "white", "red"],
  onSale: true,
  freeShippingEligible: false
});

Setting and getting attributes


Use .set() and .get() for Backbone Models

shirt.set('tagline', 'sempre ad maiora');
shirt.set('newProduct', false);
shirt.set('inventory', 1);
shirt.get('tagline'); //returns 'sempre ad maiora'
shirt.get('newProduct'); // returns false
shirt.get('inventory'); // returns 1

If you try to access Model properties via dot/bracket notation, they'll be undefined

shirt.tagline; // undefined
shirt['tagline']; // undefined

Custom initialization


var Product = Backbone.Model.extend({
  initialize: function() {
    this.set('url', 'http://products.com/' + this.get("id"));
  }
});

Custom methods


var Product = Backbone.Model.extend({
  makeSentence: function() {
    console.log("Check out our very special " + this.get('type') + ".");
  }
});

Exercise Time

Collections

What is a collection?


Defining a collection


You can define a basic Backbone Collection with .extend()

var Products = Backbone.Collection.extend();

You can also pass in an object for more configuration...

var Products = Backbone.Collection.extend({
  model: Product
});

Instantiating a collection


Pass an array of models:

var products = new Products([product1, product2, product3]);

Or pass a JSON array:

var products = new Products([
    {name: "I Love JS",
    colors: ["yellow", "black"]
    },
    {name: "Three Wolves",
    colors: ["blue"]
    }]);

Sort order


Use comparator as a property to sort a Collection

var Products = Backbone.Collection.extend({
  comparator: 'inventory' 
});

Or for something more complex, use .comparator() as a method that returns a value to sort by

var Products = Backbone.Collection.extend({
  comparator: function(model) {
    return model.get("name").toLowerCase();
  }
});

Changing a collection


Adding models:

products.add([product4, product5]);

Removing models:

products.remove(product1);

Exercise Time

Views

What's a view?


  • DOM that renders a model or collection
  • Events tied to that DOM

Defining a view


You can define a basic Backbone View with .extend()

var ProductListing = Backbone.View.extend();

You can also pass in an object for more configuration...

var ProductListing = Backbone.View.extend({
  tagName: "div", // default
  className: "product"
});

Customizing the render


var ProductListing = Backbone.View.extend({
  className: "product",
  render: function() {
    this.$el.append('<img src="http://placepuppy.it/200/200">');
    return this;
  }
});

Connecting view to model


var ProductListing = Backbone.View.extend({
  className: "product",
  render: function() {
    var imgUrl = this.model.get('imgUrl');
    var newNode = $('<img src="' + imgUrl + '">');
    this.$el.append(newNode);
    return this;
  }
});

var product = new Product({imgUrl: "http://placekitten.com/200/100"});

var listing = new ProductListing({
  model: product
});

Using the view


Create the view:

var listing = new ProductListing({
  model: product
});

Then append it:

listing.render();
$('#products').append(listing.$el);

..or...

var listingEl = listing.render().$el;
$('#products').append(listingEl);

...or...

$('#products').append(listing.render().$el);

DOM events

var ProductListing = Backbone.View.extend({
  events: {
    'mouseover img' : 'showTooltip',
    'mouseout img': 'hideTooltip'
  },
  showTooltip: function(e) {
    var tooltipDiv = $('<div class="product-tooltip">');
    tooltipDiv.html('<strong>' + this.model.get('review') + ' stars: </strong>');
    tooltipDiv.css({'position': 'absolute', 'top':  e.pageY, 'left': e.pageX});
    this.$el.append(tooltipDiv);
  },
  hideTooltip: function(e) {
    this.$('.product-tooltip').remove();
  }
});

Backbone events


Listen to Backbone events with .listenTo()

var ProductListing = Backbone.View.extend({
  initialize: function() {
    this.listenTo(this.model, 'change', this.render)
  },
  render: function() {
  // ...
  }
});

'add' 'remove' 'sort' 'change' and more...

Custom events

Trigger custom events with .trigger()

var ProductModel = Backbone.Model.extend({
  initialize: function() {
    this.trigger('ready');
  }
});

You can listen to these events, too

var ProductView = Backbone.View.extend({
  initialize: function() {
    this.listenTo(this.model, 'ready', this.render)
  },
  render: function() {
  // ...
  }
});

Exercise Time!

Handlebars


Handlebars is an HTML templating library. To use it:


1. Include handlebars.js on your page

2. Make a template script tag:

<script id="product-template" type="text/x-handlebars-template">
    <strong>{{ product.name }}</strong>: {{ product.inventory }} in stock
</script>

3. Compile the template and render it with your data:

var source   = $("#product-template").html();
var template = Handlebars.compile(source);
var litterRobot = {"name": "Litter Robot", "inventory": 20};
var rendered = template({product: litterRobot});

Backbone & Handlebars


In the HTML:

<script id="products-template" type="text/x-handlebars-template">
  {{#each products}}
    <div class="product">
      <strong>{{ name }}</strong>: {{ inventory }} in stock
    </div>
  {{/each}}
</script>

In the JS:

var ProductsListing = Backbone.View.extend({
  className: 'products',
  render: function() {
    var template = Handlebars.compile($("#products-template").html());
    var rendered = template({products: this.collection.toJSON()});
    this.$el.append(rendered);
    return this;
  }
});

var products = new Products([product1, product2]);
var listings = new ProductsListing({collection: products});

Exercise Time

The Backbone Backend

CRUD

Operation name HTTP method Backbone Model Backbone Collection
CREATE POST model.save()
READ GET model.fetch() collection.fetch()
UPDATE PUT model.save()
DELETE DELETE model.destroy()

Saving a model

.save()

var Product = Backbone.Model.extend({
  urlRoot: 'http://gdibb.herokuapp.com/products'
});

var shirt = new Product({
  desc: "GDISF Backbone.js",
  category: "t-shirt",
  price: "20",
  inventory: 10
});

shirt.save();
HTTP POST http://gdibb.herokuapp.com/products

Updating a model

.save()

shirt.set('inStock', true);

shirt.save();
HTTP PUT http://gdibb.herokuapp.com/products/<id>

Deleting a model

.destroy()

shirt.destroy();
HTTP DELETE http://gdibb.herokuapp.com/products/<id>

Getting a Collection

.fetch()

var ProductCollection = Backbone.Collection.extend({
  url: "http://gdibb.herokuapp.com/products",
  model: Product
});
var products = new ProductCollection();

products.fetch(); // sets models on the collection from the response
HTTP GET http://gdibb.herokuapp.com/products

Backend + View


var BookShelfView = Backbone.View.extend({
  initialize: function() {
    this.listenTo(this.collection, 'reset', this.render);
    this.fetch();
  },
  render: function() {
    // ...
  }
});

Exercise Time!

MV* Frameworks

Keep your options open



Figure out what's important to you:
modularity? data binding? testability? persistance?



Review your options:
Ember? Spine? AngularJS? Enyo? and many more...

There's no "right answer"

...but some are better than others.