Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

MAKE VIEWS REUSABLE - Pass in the “el” attribute var MyView = Backbone.View.extend({ }); ! new MyView({ el: ‘#putHere’ }); var MyView = Backbone.View.extend({
 el: ‘#putHere’ }); new MyView();

Slide 3

Slide 3 text

MAKE VIEWS REUSABLE - Create the container element dynamically var MyView = Backbone.View.extend({ tagName: ‘div’ }); ! $(‘#putHere’).html(new MyView({ el: ‘#putHere’ })); var MyView = Backbone.View.extend({
 el: ‘#putHere’ }); new MyView();

Slide 4

Slide 4 text

ENSURE DOM ELEMENT EXISTS - If DOM is changing, use string ‘.selector’ instead of direct reference $(‘.selector’) var MyView = Backbone.View.extend({ }); ! new MyView({ el: ‘#putHere’ }); var MyView = Backbone.View.extend({ }); ! new MyView({ el: $(‘#putHere’) });

Slide 5

Slide 5 text

ENSURE DOM ELEMENT EXISTS - Backbone will lazy evaluate the string ‘el’ // Ensure that the View has a DOM element to render into. // If `this.el` is a string, pass it through `$()`, take the first // matching element, and re-assign it to `el`. Otherwise, create // an element from the `id`, `className` and `tagName` proeprties. _ensureElement : function() { if (!this.el) { var attrs = this.attributes || {}; if (this.id) attrs.id = this.id; if (this.className) attrs['class'] = this.className; this.el = this.make(this.tagName, attrs); } else if (_.isString(this.el)) { this.el = $(this.el).get(0); } } (Backbone source)

Slide 6

Slide 6 text

CLEANUP YOUR EVENTS - Manually remove events when closing views Backbone.View.prototype.close = function(){ this.remove(); // only for views that use tagName this.unbind(); if (this.onClose){ this.onClose(); } }

Slide 7

Slide 7 text

CLEANUP YOUR EVENTS - Implement an ‘onClose’ function Backbone.View.extend({ onClose: function () { this.undelegateEvents(); // if not removing this.collection.off(); // for all event-bound state } });

Slide 8

Slide 8 text

CLEANUP YOUR EVENTS - this.model.off() only removes .on() events Backbone.View.extend({ initialize: function () { this.model.fetch({ success: render error: renderError }); } }); Backbone.View.extend({ initialize: function () { this.model.on(‘change’, this.render); this.model.on(‘error’, this.renderError); } });

Slide 9

Slide 9 text

INHERITANCE - Classic OOP subclassing of your own classes var MajesticCreature = Backbone.Model.extend({}); ! var Liger = MajesticCreature.extend({});

Slide 10

Slide 10 text

INHERITANCE - Call super() MajesticCreature.extend({ initialize: function () { this.constructor.__super__.initialize.apply(this, arguments); } });

Slide 11

Slide 11 text

INHERITANCE - Extend properties (eg, add additional events) var Place = Backbone.View.extend({ events: { ‘ride .scooter’: ‘rideScooterThruPlace’ } }); ! var SecretPlace = Place.extend({ events: _.extend({ ‘fightFor .chips’: ‘beginChipBrawl’ }, Place.prototype.events) });

Slide 12

Slide 12 text

INHERITANCE - Put different subtypes in a collection // If Liger and Nessie extend MajesticCreature ! var Creatures = Backbone.Collection.extend({ model: MajesticCreature, parse: function (res) { var self = this; _.each(res, function (creature) { switch (creature.type) { case ‘skilled-in-magic’: self.add(new Liger(creature)); case ‘underwater-ally’: self.add(new Nessie(creature)); } }); } });

Slide 13

Slide 13 text

DEVELOP WITHOUT A BACKEND - Store test data.json files locally - At the path of the eventual backend service var RipOff = Backbone.Model.extend({ url: ‘/that/place/’ }); ! var theDojoExperience = new RipOff(); theDojoExperience.fetch();

Slide 14

Slide 14 text

CHANGE THE BACKEND - backbone-localstorage - backbone-couchdb

Slide 15

Slide 15 text

BIND IN INITIALIZE - Guaranteed to run once per object var MyView = Backbone.View.extend({ initialize: function () { this.model.on(‘change’, ‘goAndDo’); },
 render: function () { // multiple-run safe } }); var huckabee = new MyView(); huckabee.render(); //ok Huckabee.render(); //ok, just monotonous var MyView = Backbone.View.extend({
 render: function () { this.model.on(‘change’, ‘goAndDo’); } }); var huckabee = new MyView(); huckabee.render(); //ok Huckabee.render(); //bad – goAndDo x 2

Slide 16

Slide 16 text

SCOPE EVENTS WITH SUBVIEWS - Easily get to model in question var ListView = Backbone.View.extend({ // handles fetching collection render: function () { // instantiate model-level views // they ea. render, append to DOM } }); var ModelInListView = Backbone.View.extend({ events: { ‘click .edit’: ‘editModel’ }, editModel: function() { this.model.doEdityThings(); } }); var ListView = Backbone.View.extend({ // handles fetching collection events: { ‘click .model .edit’: ‘editModel’ } render: function () { // render each model in collection in this el }, editModel: function (evt) { var indx = this.$(‘.model).index($ (evt.currentTarget)); this.collection.at(indx).doEdityThings(); } });

Slide 17

Slide 17 text

COMMUNICATE BETWEEN OBJECTS - Commit to not using globals - Unless it’s really global; and then, don’t clutter

Slide 18

Slide 18 text

COMMUNICATE BETWEEN OBJECTS - Pass reference var QuestionView = Backbone.View.extend({ initialize: function () { this.answerSheet = this.options.answerSheet; } answerQuestion: function () { var answer = determineAnswer(); this.answerSheet.recordAnswer(answer); } }); ! var AnswerSheet = Backbone.Model.extend({}); ! var myAnswers = new AnswerSheet(); var newQuestion = new Question({ answerSheet: myAnswers });

Slide 19

Slide 19 text

COMMUNICATE BETWEEN OBJECTS - Talk over global Backbone.Events var QuestionView = Backbone.View.extend({ initialize: function () { this.answerSheet = this.options.answerSheet; } answerQuestion: function () { var answer = determineAnswer(); Backbone.Events.trigger(‘answered’, answer); } }); ! var AnswerSheet = Backbone.Model.extend({ initialize: function () { Backbone.Events.on(‘answered’, this.recordAnswer); } }); ! var myAnswers = new AnswerSheet(); var newQuestion = new Question();

Slide 20

Slide 20 text

MODEL NEWNESS - Model has isNew() function - Not magic: isNew: function() { return this.id == null; }

Slide 21

Slide 21 text

MODEL NEWNESS - Controls HTTP method when calling model.save() - isNew(): HTTP POST /model/url/ HTTP PUT /model/url/id - !isNew():

Slide 22

Slide 22 text

REMEMBER WHO YOU ARE - Manage the fact that ‘this’ changes - Pass context in event binding Backbone.View.extend({ initialize: function () { this.model.on(‘change’, this.render, this); } render: function () { this.model.getStuffAndMakeHtml() ; // #ftw } }); Backbone.View.extend({ initialize: function () { this.model.on(‘change’, this.render); } render: function () { this.model.getStuffAndMakeHtml() ; // #fail } });

Slide 23

Slide 23 text

REMEMBER WHO YOU ARE - Capture the context once for all your functions Backbone.View.extend({ initialize: function () { _.bindAll(this); this.model.on(‘change’, this.render); } render: function () { this.model.getStuffAndMakeHtml(); // #ftw } });

Slide 24

Slide 24 text

ORGANIZE YOUR FILES - Use an AMD loader, like RequireJS define(function () { return Backbone.Model.extend({}); }); define([‘Luchador’], function (Luchador) { return Backbone.Collection.extend({ model: Luchador }); }); Luchador.js Luchadors.js

Slide 25

Slide 25 text

MINIMIZE DOM OPERATIONS - They’re expensive. Use a disconnected DOM fragment Backbone.View.extend({ render: function () { this.$el.html(‘’); var frag = document.createDocumentFragment(); _(this.collection.models_.each(function (model) { frag.appendChild(createHtml(model)); }); this.$el.html(frag); } }); Backbone.View.extend({ render: function () { var self = this; _(this.collection.models_.each(function (model) { self.$el.append(createHtml(model)); }); } });

Slide 26

Slide 26 text

BIND IN INITALIZE - This is the verbage - Everyone can read this, right? vertebrae = -> alert “super awesome”

Slide 27

Slide 27 text

jaketrent.com @jaketrent Henry Gray http://en.wikipedia.org/wiki/File:Gray94.png http://www.bartleby.com/107/illus111.html Public Domain ! WebTreats, etc. http://webtreatsetc.deviantart.com/art/9-Blue-Striped-Patterns-131303428 Free for personal/commercial ! Jeremy Ashkenas https://github.com/documentcloud/backbone/blob/master/LICENSE MIT license ! Dave Geddes, Jason LuBean, and Matt Werny For their topic suggestions