Basics of Backbone
In the past month I've learned too much about Backbone to write in one blog post, but just figuring out how all the files talk to each other was the main challenge and so I've summarized that here. DISCLAIMER: This is an untested example just meant to show how the various Backbone components hook up.
Firstly, Backbone is an MVC style framework but like Django it's more MTV. No, I'm not talking about Music Television, what I'm saying is the models are still called models but the view is called a template and the controller is called a view. Please relax.
Assume we have a book api. We can get a single book's attributes with a GET request to /api/book/:id or we can GET all of the books at /api/book. Sending a POST request to /api/book creates a new book object. Sending a POST request to /api/book/:id updates an existing books attributes.
A basic book model.
Important features:
url —> tell the model how to get it’s attributes from the api
book.js
define([ 'jquery' , 'backbone' ], function ($, Backbone) { var Book; Book = Backbone.Model.extend({ defaults: { // not necessary but a good way to keep track of the attributes we expect to get back from the api response id: null, title: null, author: null } , url: function () { if (this.get('id')) { return "/api/book/" + this.get('id'); } else { return "/api/book"; } } }); return Book; });
The url tells the model where to send it's get/post requests. These requests will be sent with all of the models attributes to the api.
A basic book collection. This is just a handy way of packaging up a bunch of book models.
Important features:
model —> tell the collection what model to use
url —> tell the collection how to get the models from the api
bookCollection.js
define([ 'jquery' , 'backbone' , 'modules/book/models/book' // tell backbone where to find the model ], function ( $ , Backbone , Book // tell backbone what we'll be calling the model ) { var BookCollection; BookCollection = Backbone.Collection.extend({ model: Book, url: function () { return '/api/book'; }, onInitialize: function(models, options) { // here you have access to all the models // any options we passed when we created the collection in app.js are also accessible here. } }); return BookCollection; })
Use onInitialize to add to but not overwrite the initialize function of the backbone class you are extending. onInitialize runs right after the parent class's initialize.
A basic book view.
Important features:
tagName --> tell the view what html element to render the model in
className --> tell the view what class to give the model element
template --> tell the view where to render the model
bindings --> tell the view to listen for changes in the model
bookView.js
define([ 'jquery' , 'backbone' ], function ( $ , Backbone ) { var BookView; BookView = Backbone.View.extend({ tagName: 'div' // the model will be rendered in a div , className: 'book' // the class of the div will be .book , events: { 'click .like': 'like', // you can add events but I'm not going to get into this } , template: 'book-template' // tell the view what template to use , bindings: function () { // the view listens for changes in the model and updates when the model changes this.listenTo(this.model, "change", this.render); } , like: { // do some stuff when the user clicks the like button } }) return BookView; });
A basic book collection view.
important features:
className —> tell the colection view the class name to give the div that holds the collection
modelView —> tell the collection view which view to use for each model in the collection
template —> tell the collection view which template to render everything in
contentSelector —> tell the collection view which html element to render the collection in
bindings —> add a listener to tell the collection view to listen for changes in the collection
bookCollectionView.js
define([ 'jquery' , 'backbone' , 'modules/book/views/bookView' // tell the collection view about the model view ], function ( $ , Backbone , BookView ) { var BookCollectionView; BookCollectionView = Backbone.View.extend({ className: 'book-list' // since no tagName is specified, backbone defaults to div, this will be the class for the div , options: { cutoff: 10 } , modelView: BookView // tell it about the model view , template: 'book-collection-template' // tell it where to render , contentSelector:'.book-container' // tell it what part of the template to render in , bindings: function () { this.listenTo(this.collection, "reset", this.render); // re-render the collection when the collection model changes, e.g. we could filter the books to only show books by a certain author } , onRender: function () { // similar to onInitialize, you can add functionality on render without overwriting backbone's View render } , events: { // you can have events } }); return BookCollectionView; });
templates just need an id matching the string given in the view.
_book.jade
script(type='text/template', id='book-template') // template code goes in here
_bookCollection.jade
script(type='text/template', id='book-collection-template') .book-container // collection will render in here
Tell everything to grab it's stuff in app.js.
Basically, initialize an empty BookCollection when the app loads and then fill it with a book model for each book in the database. Also, start up the router so that our backbone app can respond to different routes.
app.js
define([ 'backbone' , 'domReady' , 'router' , 'modules/followable/collections/bookCollection' ], function (Backbone , domReady , Router , BookCollection ) { // I'm not exactly sure how this works but I think // it's making all of this stuff available globally in the page window window.Delve = _.extend(window.Delve, { Models: {} , Collections: {} , Views: {} , Routers: {} , Constructors: {} , Utils: Utils , init: function (options) { var that = this; // Grab book objects this.Collections.BookCollection = new BookCollection([], {user_id: 1}); // takes models and options as params. this.Collections.BookCollection.fetch(); // grabs all the models from the api specified in the collection url // Create new app router domReady(function () { that.Routers.App = new Router(); Backbone.history.start({ root: '/' }); }); } }); });
Tell it when to do all this in router.js.
Important features:
routes —> tell the router which function to run when it hits a given route
bookCollection —> this is the function I’ve written to be run for the book route
initialize —> I’m not sure how much is built into Backbone and how much you need to set up, for now I’m going to ignore this part but I assume it is important.
router.js
define([ 'jquery' , 'backbone' , 'modules/followable/views/bookCollectionView' ], function( $ , Backbone , BookCollection ) { var Router; Router = Backbone.Router.extend({ initialize: function( collection ) { console.log("In router.js"); // Instantiate new view this.view = // I didn’t set up this part so I’m going to ignore it for now this.view.render(); } , bookCollection: function (id) { this.relevantIds.book = id; // you can pass in extra info from the url this.view.showPage(new BookCollection(this.relevantIds, window.AppName)); } , routes: { ‘book(/:id)': ‘bookCollection' } }); return Router; });
Ok, that was a lot so here is my favorite cat gif:










