Build a Contacts Manager Using Backbone.js: Part 1

Build a Contacts Manager Using Backbone.js: Part 1

Tutorial Details
  • Applications Used: Backbone.js, jQuery
  • Difficulty: Intermediate
  • Completion Time: 30 Minutes

Final Product What You'll Be Creating

This entry is part 1 of 5 in the Getting to Know Backbone.js Session
Next »

In this tutorial, we’re going to look at building a fully functional contacts manager using Backbone.js, Underscore.js, and jQuery. We’ll take a look at the basic components that make Backbone tick as well as some of the convenience methods exposed by Underscore.


What Exactly Are All These Libraries?

Backbone is an architectural framework that allows us to easily create non-trivial JavaScript applications using MVC-style organisation and structure. Backbone isn’t considered true MVC – C is for Collection not Controller, but it still offers many of the same benefits and enables us to write powerful yet maintainable code.

Underscore is a utility library that provides enhanced functionality to JavaScript, adding additional functions for working with arrays, collections, functions and objects.

I’m sure jQuery needs no introduction here.


Getting Started

We’ll need a root project folder containing css, img and js subfolders, so go ahead and create these now. We’ll start out with the following HTML page:

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Backbone.js Web App</title>
        <link rel="stylesheet" href="css/screen.css" />
    </head>
    <body>
        <div id="contacts"></div>
        <script src="js/jquery-1.7.1.min.js"></script>
        <script src="js/Underscore-min.js"></script>
        <script src="js/Backbone-min.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>

Save this as index.html in the root project folder. Backbone’s only mandatory requirement is Underscore.js, but we’ll also want to make use of jQuery so we link to these two libraries before Backbone. Our application’s code will go into app.js and any styles will go into screen.css. On the page, we’ve got an empty container that will form the basis of our application.

Next we can create the skeletal JavaScript file that we’ll gradually fill out over the course of this series. In a new file add the following code:

(function ($) {

    var contacts = [
        { name: "Contact 1", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
        { name: "Contact 2", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
        { name: "Contact 3", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "friend" },
        { name: "Contact 4", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "colleague" },
        { name: "Contact 5", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
        { name: "Contact 6", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "colleague" },
        { name: "Contact 7", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "friend" },
        { name: "Contact 8", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" }
    ];

} (jQuery));

Save this in the js folder as app.js. We’ll put all of our code in an anonymous function which we invoke immediately, aliasing jQuery as the $ character. Also defined at this stage is an array of objects where each object represents a contact.

We’ll use this local data store for this part of the tutorial as it allows us to get some script up and running without worrying to much about syncing with a server. We’ll save that for another day!


Models

A model represents the data of an application; in our application this will be an individual contact, which will have attributes such as a name, a contact number, etc. You could say that an individual model represents the atomic part of the application – the smallest possible unit of functionality. Add the following code directly after the data array:

var Contact = Backbone.Model.extend({
    defaults: {
        photo: "/img/placeholder.png"
    }
});

To create a model in Backbone we just extend the Backbone.Model class using the extend() method. We can pass an object into the method which allows us to customize the model with our own functionality. One of the properties we can set within this object is called defaults. This property allows us to configure default values for any attribute that we would like our models to have.

In this case, we set a placeholder image as the default value of the photo attribute for model instances. Any models that don’t have this attribute when defined will be given it.

Models have other properties that we can use to add functionality; we could define an initialize() method, and this method would be invoked automatically by Backbone for us when each model is initialized. We won’t make use of this at present, but don’t worry, we’ll come back to models a little later on.


Collections

A collection is a class for managing groups of models. We’ll use a simple one in this example to store all of our contacts. Add the following code directly after the Contact model:

var Directory = Backbone.Collection.extend({
    model: Contact
});

Like a model, a collection is a Backbone class that we extend to add custom functionality specific to our application. Collections also have an extend() method, and it accepts an object that allows us to set properties of the class and add behaviour. We use the model property to tell the collection what class each item in the collection should be built from, which in this case is an instance of our Contact model. Don’t worry that the classes we’ve defined so far seem extremely simple, we’ll be coming back and adding additional functionality in later parts of the tutorial.


Views

Views are responsible for displaying the data of the application in an HTML page. One of the benefits of separating out the parts of the application that process the data and the parts that display the data is that we can very easily make a change to one, without requiring extensive changes to the other. We’ll use a couple of views in our application, the first of which should be added directly after the Directory class:

var ContactView = Backbone.View.extend({
    tagName: "article",
    className: "contact-container",
    template: $("#contactTemplate").html(),

    render: function () {
        var tmpl = _.template(this.template);

        this.$el.html(tmpl(this.model.toJSON()));
        return this;
    }
});

This view handles displaying an individual contact. Just like models and collections, views have an extend() method used to extend the Backbone.View class. We set several instance properties in our view; the tagName property is used to specify the container for the view and the className properties specifies a class name that is added to this container. We’ll use a simple template in our HTML file to render each contact, so the template property stores a cached reference to the template, which we select from the page using jQuery.

Next we define a render() function; this function isn’t invoked automatically by Backbone and while we could call it from the automatically invoked initialize() method to make the view self-rendering, we don’t need to in this case.

Within the render() method we store a reference to Underscore’s template() method and pass to it the stored template. When passed a single argument containing a template Underscore doesn’t invoke it immediately but will return a method that can be called in order to actually render the template.

We then set the HTML content of the <article> element created by the view to the interpolated template using jQuery’s html() method for convenience. This is done by calling the templating function that Underscore returned previously and passing it the data to interpolate. The data is obtained from the model using Backbone’s toJSON() method on the model. Interpolating just means that the tokens within the template are replaced with actual data. Notice also that we use $el to set the HTML content; this is a cached jQuery object representing the current element so that we don’t have to keep creating new jQuery objects.

At the end of the render() method, we return the this object, which points to the view instance that the render() method is called on. This is so that we can chain other Backbone methods to the view instance after calling its render() method.


Micro Templating With Underscore

Now would probably be an appropriate time to look at Underscore’s built-in micro-templating facitlities. Underscore provides the template() method as we saw to consume and interpolate templates. To the HTML page we should add the template that we will use; add the following code directly after the contacts container <div>:

<script id="contactTemplate" type="text/template">
    <img src="<%= photo %>" alt="<%= name %>" />
    <h1><%= name %><span><%= type %></span></h1>
    <div><%= address %></div>
    <dl>
        <dt>Tel:</dt><dd><%= tel %></dd>
        <dt>Email:</dt><dd><a href="mailto:<%= email %>"><%= email %></a></dd>
    </dl>
</script>

We use a <script> element with an id attribute so that we can easily select it, and a custom type attribute so that the browser doesn’t try to execute it. Within the template we specify the HTML structure we would like to use, and use <%= model_property_name %> tokens to specify where the model data should be inserted. There are a couple of other features we can make use of with Underscore including interpolating HTML-escaped values, or executing arbitrary JavaScript, but we don’t need to make use of these for the purpose of this tutorial.


A Master View

To finish off this part of the tutorial we going to create one more view. Our current view represents each individual contact so is mapped to a model on a 1:1 basis. But this view isn’t self-rendering and we haven’t invoked it yet. What we need is a view that maps 1:1 to our collection, a master view that will render the right number of contact views to display each of our contacts. Directly after the ContactView, add the following class:

var DirectoryView = Backbone.View.extend({
    el: $("#contacts"),

    initialize: function () {
        this.collection = new Directory(contacts);
        this.render();
    },

    render: function () {
        var that = this;
        _.each(this.collection.models, function (item) {
            that.renderContact(item);
        }, this);
    },

    renderContact: function (item) {
        var contactView = new ContactView({
            model: item
        });
        this.$el.append(contactView.render().el);
    }
});

This view will be attached to an element that already exists on the page, the empty container that is hard-coded into the <body>, so we select the element with jQuery and set it as the el property. When then define a simple initialize() function which creates an instance of our collection class and then calls its own render() method, making this view self-rendering.

We then define the render() method for our master view. Within the function, we store a reference to the view so that we can access it within a callback function, and then use Underscore’s each() method to iterate over each model in our collection.

This method accepts two arguments (in this form, although it can also be used with just one argument); the first is the collection of items to iterate over, the second is an anonymous function to be executed for each item. This callback function accepts the current item as an argument. All we do within this callback function is call the renderContact() method and pass to it the current item.

Lastly we define the renderContact() method. In this method we create a new instance of our ContactView class (remember, the ContactView class represents an individual contact) and set its model property to the item passed into the method. We then append the element created by calling the view’s render() method to the $el property of the DirectoryView master view (the empty container we selected from the page). The $el property is a cached jQuery object that Backbone creates for us automatically.

The master view is responsible for generating each individual model within our collection. All we need to do is initialise our master view, and because it is self-rendering, it will display all of the contacts specified in the array of dummy data:

var directory = new DirectoryView();

When we run this page in a browser now, we should see a visual representation of our data:

Backbone creates an instance of a model for each item in our original array, which are stored in our collection and rendered as an instance of a view.

This tutorial isn’t about CSS, so I haven’t covered the example CSS at all. It’s just basic CSS, if you’re curious take a look at the style sheet included in the demo archive.


Summary

In this part of the tutorial we’ve been introduced to some of the core components of Backbone.js; models, collections and views. Models are classes that we can create in order to store data about a particular thing and define behaviour for it. Collections are used to manage groups of models and views allow us to render our models using interpolated templates that display the data from our models.

In the next part of the tutorial we’ll take a look at how we can filter our collection to display only a subset of our models. We’ll also take a look at another major component of Backbone – Routers.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://nodejs-news.com Vincent RABAH

    Awesome demo!

    But line 18 I changed :

    photo: “/img/placeholder.png” by photo: “img/placeholder.png” !

    Another really funny thing : if you look at the source code of the page generated by your web browser, you got the template and not the render code ?!! Strange :)

    Regards,
    Vincent RABAH

    • Diego

      Because your looking at the source code before javascript rendering (its the original server response)…
      Use any king of webdebug and you should see the new elements.

      To be like you want the page should be parsed server-sided :)

  • http://pressedweb.com Cory

    Demo isn’t rendering images (for me anyway). Heading out the door right now, but I’ll read this over when I get back. I love Underscore. :)

    • http://pressedweb.com Cory

      Remove the forward slash in your code before img and it should work.

  • Ryan

    Just be careful when teaching bad habits of Backbone, we see this all the time.

    var tmpl = _.template(this.template); within the render method is a really huge performance hit.
    It means underscore has to “consume and interpolate templates” every time a ContactView is rendered.

    You only need to “consume and interpolate templates” once so it is far better to do that directly in the template variable of the view itself for that reason.

    • Felix

      Hi.

      May you code your approach here?. Thanks in advance.

    • Backbone Newbie

      Hi Ryan, How would you have coded it?

    • http://ecmazing.com Šime Vidas

      I wanted to comment on the same thing. Should be

      template: _.template( $( ‘#contactTemplate’ ).html() ),

      and then

      $( this.el ).html( this.tmplate( this.model.toJSON() ) );

      • ray hunter

        Šime (or Ryan),
        can you elaborate on why calling _.template(this.template); with the this.template defined prior to the render() method is a larger performance hit than _.template( $( ‘#contactTemplate’ ).html() )?

      • ian

        Anyone want to confirm the reason here? If I’m understanding correctly, the render function gets called on the ContactView object for every contact in the collection so that would be 8 copies of var tmpl and 8 times telling underscore to get the template? So setting it once as a property of the ContactView obj and then using this.template avoids this?

        template: _.template( $(‘#contactTemplate’).html()),

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

        Does the _.each call to renderContact not create a completely new ContactView for each item? That’s got me wondering about performance too.

    • http://www.danwellman.co.uk Dan Wellman

      Thanks for reading, and sharing improvements to the code :)

  • Kevin

    Finally! A decent Backbone tutorial NOT written with CoffeeScript

  • msankhala

    Haven’t you tested the code before publishing. Its irritating when you see broken demo.

    • http://www.danwellman.co.uk Dan Wellman

      There is a minor issue with the images not being displayed because the example is not hosted directly under the root of the nettuts site. Other than that the demo is working perfectly – if it wasn’t none of the contacts would be displayed :)

    • Orijit

      Thanks for the great tutorial Dan. Serves as a GREAT introduction to Backbone.

      A lot of people here have complained about missing images (something that I encountered as well), but cmon guys, you could have sorted it out yourself anytime. No Big Deal. It overshadows the value of this article IMO.

    • Alchemication

      Took me 5 seconds to figure out the “/” before img tag (and I’m working as Web Developer for 4 months) ;D

      Good luck…

  • Amit Erandole

    Finally a proper backbone tut from nettuts. Please make this into a running series like you did with codeigniter and ruby. There is a huge audience invested in this

  • http://www.prestaspirit.fr Prestaspirit

    This tutorial is really interresting!
    thank you

  • http://www.funcion13.com Antonio Laguna

    All clear except for the this.$el.append(contactView.render().el);

    Why that el is preceded by a dollar sign and why contactView.render() chains to .el?

    • http://tbranyen.com Tim Branyen

      In Backbone 0.9 the $el property was introduced to automatically provide a jQuery-version of the View’s element. So this is equivalent to saying $(this.el).

    • http://www.danwellman.co.uk Dan Wellman

      @antonio el is proceeded by $ because it’s a jQuery object. Backbone creates this for us if jQuery is available. el is the element returned by ContactView.render() so when ContactView.render().el is passed to jQuery’s append() method, it gets appended to the DirectoryView.

      Makes sense?

      • http://www.funcion13.com Antonio Laguna

        So much sense!

        Thank you very much for the explanation.

      • ian

        Thank you for clearing that up. I went through a wine cellar app tutorial that was re-written and the original used $el but in the new rewrite the guy used $(this.el) but forgot to replace one of them so I was confused as to how it was working but went ahead and changed it to make the code consistent.

        I prefer $(this.el) because I’m used to that way but using the new backbone way will depend on if it is more efficient or becomes common practice I guess. I think the jquery way is more obvious when reading code but like I said that’s because it’s what I’m used to.

  • Matthew Laver

    Good Tutorial Dan, keep them coming. I’m really liking Backbone at the moment.

    Would be great if you could touch on Local Storage and Database hookup at some point in the future.

    Thanks again.

    • http://www.danwellman.co.uk Dan Wellman

      Thanks for reading :)

      Yes, I am planning a part that changes the test data store (the local array) used in parts 1-4 into a proper db solution…stay tuned!

      • WCravens

        Am I missing something? It looks like three:

        From the docs:
        _.each( list, iterator, [context] )

        From the example:
        _.each( this.collection.models, function (item) {… }, this )

      • http://www.danwellman.co.uk Dan Wellman

        @wes nope, I was missing something, apologies. It does of course take three arguments

  • WCravens

    Great tutorial. backbone.js is providing something I’ve only been able to daydream about for years! Good Tutorials are critical to it’s success.

    I do think there may be a small editorial fix though:

    In ‘A Master View’… paragraph starting “This method accepts two arguments”… should this not be ‘three’ arguments?

    • http://www.danwellman.co.uk Dan Wellman

      Absolutely correct, _.each() may accept three arguments.

      What I meant to say was that in this example it accepts 2 arguments.

      Thanks for reading :)

  • http://deeptechtons.com Deeptechtons

    neat fun app to say, but the url to placeholder.png is broken in the demo app. Should correct that i presume

    • http://www.danwellman.co.uk Dan Wellman

      The image in the demo is broken because when writing the demo locally the img directory is directly under the root. The path is ‘root relative’ as it were. When the demo is hosted, the img directory is no longer sitting directly under the root. If you download the example code it should run as expected :)

  • Andrew

    var DirectoryView = Backbone.View.extend({
    el: $(“#contacts”),

    I think ‘el’ here suppose to be:

    el: document.getElementById(‘contacts’),

    From Backbone.js docs:
    $el
    A cached jQuery (or Zepto) object for the view’s element. A handy reference instead of re-wrapping the DOM element all the time.

    • http://www.danwellman.co.uk Dan Wellman

      document.getElementById(“id”) is exactly equivalent to $(“#id”). The el property of a view either refers to an individual instantiation of a view (if el is not explicitly specified), or it is an element that you specify.

      In the ContactVirew class el is the container given to each instance of a contact and we specify that it should be an <article> element using the tagName property. There is only one DirectoryView instance, and rather than creating a new element for it (using the tagName property again), we specify an existing container on the page.

  • Andrew

    In ‘DirectoryView’ you don’t need to specify ‘that’. ‘this’ in ‘this.collection.models’ points to ‘DirectoryView’, and ‘this’ inside of the iterator function (‘this.renderContact’) points to ‘DirectoryView’ too, since you’re passing it as a third parameter to ‘_.each’

    var DirectoryView = Backbone.View.extend({

    render: function() {
    _.each( this.collection.models, function( item ) {
    this.renderContact( item );
    }, this );
    },

  • Christopher Thielen

    Hopefully a simple question: what if, in the course of the page’s existence, I add another contact to the contacts array? How do I re-render the view? Calling directory.render() seems to make a second view, not update the original.

    • mcrk

      I’m sure this will be covered in next parts.

      • http://www.danwellman.co.uk Dan Wellman

        It definitely will be covered, but you’ll have to wait for part 3 ;)

  • http://www.thomaskuipers.nl Thomas Kuipers

    Props for not including the CSS into the tutorial, I always find that an annoying distraction but everyone still does it.

    • http://www.danwellman.co.uk Dan Wellman

      Thanks, I feel that the CSS is way too arbitrary in most cases to worry about covering in this kind of a tutorial. In any block of functionality that you download, in the form of a plugin or some code to do a specific thing, the CSS is always the bit that you have to change to make it fit with whatever you’re building anyway :)

  • Tony

    Very cool !

    More please :p

  • klaus

    nice tut, waiting for the other parts! ;-)

    and also nice code improvements in the comments – should be mentioned in the original code :)

  • kete

    Hi,

    why the use of “text/template” and not “text/html” in the type tag of the template? I’m not saying that is an error, I’m just curious.

    Looking forward for the next part.

    Thanks!

    • kete

      Sorry, I meant “type attribute” not “type tag”

      • http://www.cssian.com KevinM

        We say “type=text/template” so that the browser’s parser doesn’t try to render the code as HTML or run the code as a script.

    • name

      why not.

      • the king

        because it’s a framework

  • JP

    What name should the model file have and where should it be placed? Same goes for views, etc.
    You might want to add this in the tutorial :(

    • http://www.danwellman.co.uk Dan Wellman

      app.js is the name of the code file as stated at the start of the tutorial. There isn’t a separate file for models, one for views etc.

  • http://twitter.com/jackbach Jack Bach

    Some tips:

    If you set a context to _.each, the closures trick (using that) is not needed. So you could simply use this inside the iterator:

    // DirectoryView.render
    _.each(this.collection.models, function (item) {
    this.renderContact(item);
    }, this);

    On the other hand, backbone collections are sugared with some underscore methods. So you could also use:

    // DirectoryView.render
    this.collection.each(function (item) {
    this.renderContact(item);
    }, this);

    For me, the last options is much cleaner.

    Happy coding! :)

  • Steve R

    I downloaded the source code and it does not look like the performance bug fix that Sime and Ryan proposed has been put into it. Since this sounds like a big bug/fix can the author post the amended solution so the demo is up to date?

    thank you.

  • http://www.samarpanda.com Samar

    I found some bug while compiling the code. Would like to post my fixes for this

    ContactView changed to :

    var ContactView = Backbone.View.extend({
    tagName: “article”,
    className: “contact-container”,
    template: _.template($(“#contactTemplate”).html()),

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

    DirectoryView changed to :

    var DirectoryView = Backbone.View.extend({
    el: $(“#contacts”),
    initialize: function(){
    this.collection = new Directory(contacts);
    this.render();
    },
    render: function(){
    var that = this;
    _.each(this.collection.models, function(item){
    that.renderContact(item);
    }, this);
    },
    renderContact: function(item){
    var contactView = new ContactView({
    model: item
    });
    $(this.el).append(contactView.render().el);
    }
    });

    Above changes fixed all problems for me. Hope you guys have a nice time starting backbone.js.
    Thanks.

  • http://tareq.wedevs.com Tareq

    May be you did a mistake here at this.$el.append(contactView.render().el);. Should be $(this.el). It’s okay in source code, but wrong in the article.

    • Alchemication

      in Backbone: this.$el === $(this.el)

  • http://vincentmac.com Vincent Mac

    Thanks for the great tutorial Dan. I’m looking forward to part 5.

    For those interested, I’ve created a Node.js (with Express.js and LESS) implementation of this tutorial and hosted it on github. As of right now, it is current up to part 4.

    I’ve made a couple of minor modifications (things like correcting a couple of typos where the written tutorial varies from the source) and added some of the recommendations other people have made in the comments.

    I have also updated the saveEdits function (part 4 of the tutorial) so that it re-renders the select filter. Previously, if you added a new type for a contact, it would not show up in the filter.

    Github Repo: https://github.com/vincentmac/ContactManager

  • David

    Very nice, for never doing anything (literally, nothing!) with Backbone before this made a ton of sense. Cheers!

  • JT

    Doesn’t inspire confidence when a quick test of the demo could have picked up the non-loading pics.

    The best tip ever:

    test…debug… repeat until everything works

  • http://bitly.com/powwebcom Mia Lazar

    Nice design, BTW demo missing images.

  • ramon

    you should try to replace the app.js line:18

    from: photo: “/img/placeholder.png”
    to: photo: “img/placeholder.png”

    just remove the slash ; )

  • Alan

    Hi Dan,

    I wonder if there’s alternative to append each contact view to the contact’s container. I can see that in directory’s render method, you appends them one by one instead of ‘bulk’ append, It can cause significant performance hit, can’t it?

    • http://twitter.com/doobinay Bastien Chamagne

      Yeah sure, you can always optimize, but it affects readability. Use a string to store all the contacts views and append it at the end.

      render: function(){
      var contacts = “”;
      _.each(this.collection.models, function (item) {
      var contactView = new ContactView({
      model: item
      });
      contacts += contactView.render().el;
      }, this);
      this.$el.append(contacts);
      }

  • http://railwayjs.com Anatoliy Chakkaev

    From my point of view

    var DirectoryView = Backbone.View.extend({
       … n lines
       render: function () {
           var that = this;
           _.each(this.collection.models, function (item) {
               that.renderContact(item);
           }, this);
       },
       … k lines
    });

    should be just:

    DirectoryView.prototype.render = function render() {
       this.collection.models.forEach(this.renderContact.bind(this));
    };

    advantages:

    - less code
    - I see that render methods belongs to DirectoryView without scrolling n lines up
    - have no unnecessary _ dependency

  • Rajesh

    Awesome tut for a beginner. Thanks !!

  • Rashad

    Thanks for the tutorial. Could you show an example of how you would load the json data externally?

  • http://twitter.com/gnarc ganar

    I love this tutorial, it has been quite helpful, BUT: there are subtle and also quite important differences between what is published on the page and what is on the downloadable demo files. This differences make the tutorial very hard to follow, because there are things that simply don’t work as explained here.

    Please update the tutorial to reflect what is on the demo and everithing will be ok.

    Regards

  • Abhishek Dwivedi
  • Chandra

    I tried to follow the given steps and create the same application. But it doesnt work. No script errors. Need help regarding where the problem might be .

    • Peter

      Chandra

      I followed the steps and it worked perfectly for me (even better with the template declaration tweak suggested above for the view) and removal of that leading slash in front of the img declaration in the model.

      Have you tried comparing the code you had after working through the tut, with the downloadable source files?

  • kmil0v

    I was waiting for something like this to get an idea of how the Views works. Thanks!

  • johndurbinn

    Why are you liberals always trying to change the way we do development? We need to go back to the time of real conservatives, when we would write out own backend infrastructes.

    • Nene

      There is no one way of doing things…. If you want to be conservative fine. If someone wants to be liberal let them be. No one way is the best.

  • SPeed_FANat1c

    small mistake in


    var Contact = Backbone.Model.extend({

    defaults: {

    photo: "img/placeholder.png"

    }

    });

    before img does not have to be / – otherwise error

  • tounder

    Great Tutorial. Why are so many people complaining about the leading slash on your image url? If you don’t know how relative url’s work, you should probably learn the basics instead of backbone.js

  • tre

    ola

  • stefan

    is not a framework

    • The Queen

      Its a library rather than a framework. You just use the objects it provides however you want.. is less restrictive. This is important point i think.

    • antonino from the school

      it is a framework, not a library

    • mine

      why?

  • d!xx

    Great article. I have on question. How can I replace the image with a canvas item?

  • http://twitter.com/gioarvan Panos Arvanitis

    Thanks! it was very helpful to me