Introduction to Backbone.js Part 2: Views – Video Tutorial

Backbone.js Views Video TutorialLast week you saw a video tutorial on using Models in Backbone.js. This week we've moved right along to part 2: learning about Views in Backbone.js. As usual, Backbone.js has made things super simple, yet you get a lot for how little code you write. You'll see how to attach events (super easy) and utilize models (also super easy) to give your views some data to work with.

Backbone.js Video Tutorial Series

Final HTML Code

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>Learning About Backbone.js Views</title>
    <style type="text/css">
        #container { padding:20px; border:1px solid #333; width:400px; }
        #list-template { display:none; }
    </style>
</head>
<body>

<div id="container">
    <button>Load</button>
    <ul id="list">
    </ul>
</div>

<div id="list-template">
<li><a href=""></a></li>
</div>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/backbone/backbone-min.js"></script> 
</body>
</html>

Final JavaScript Code

model = new Backbone.Model({
    data:[
        { text: "Google", href: "http://google.com" },
        { text: "Facebook", href: "http://facebook.com" },
        { text: "Youtube", href: "http://youtube.com" }
    ]
});

var View = Backbone.View.extend({
    initialize: function () {
        this.template = $('#list-template').children();
    },
    el: '#container',
    events: {
        "click button": "render"
    },
    render: function() {
        var data = this.model.get('data');
        
        for (var i=0, l=data.length; i<l; i++) {
            var li = this.template.clone().find('a').attr('href', data[i].href).text(data[i].text).end();
            this.$el.find('ul').append(li);
        }
    }
});

var view = new View({ model: model });

Conclusion

Judging by comments posted on the introductory post to these tutorials, people seem to be anxious to see the entire series, so I've decided that both of next week's posts will be continuing this series with more video tutorials. Then I'll take a break for either one post or two before walking you through a full Backbone.js app.

Backbone.js Video Tutorial Series

About the Author

Author: Joe Zim

Joe Zim

Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.


  • http://twitter.com/dtang85 David Tang

    Great tutorial! I like that you aren’t using underscore to teach Backbone. Im sure underscore is useful, but the way you’ve done it makes learning just Backbone easy.

    • Tony

      These tuts are a blast to do and mess around with, Joe give sublime text2 a try, you’re going to love it

      • http://www.joezimjs.com Joe Zimmerman

         I actually have been giving Sublime Text 2 a try, but I can’t pay for it and having the message asking me to buy it pop up in the middle of a video isn’t exactly very professional-like.

      • McWrait

        Whats wrong with notepad++?

        • http://www.joezimjs.com Joe Zimmerman

          There’s nothing wrong with Notepad++. Sublime Text just offers a lot of productivity through shortcuts and such that Notepad++ doesn’t, so it has become the “must use” code editor these days.

  • http://twitter.com/lucdew lucdew

    Thanks, very interesting.
    I am just curious, what Notepad++ plugins are you using for Javascript ?

    • http://www.joezimjs.com Joe Zimmerman

      I’m not actually using any plugins for JavaScript. I enabled auto-complete in the settings (which is actually more of a nuisance than anything most of the time). I do have a Zen Coding plugin for html though, which is super awesome.

  • http://twitter.com/ivanfdezperea Iván Fernández

    Nice tutorial!!

  • Tom Shaw

    Cool tutorial. I actually had problems getting the render to fire and solved by waiting for the DOM to load completely.

    $(function() { // After the DOM has loaded.  new View({model: sites});});

    Thanks for the great work!

    • http://www.joezimjs.com Joe Zimmerman

      If you notice, all my scripts are at the bottom of the body tag. This has a couple benefits:
      1) It allows the JavaScript code to load without blocking other parallel downloads. 
      2) You never need to check for a DOM Ready event because the DOM will always be fully loaded by that point.

  • Paul Iannazzo

    i think it would be better practice to pass the model/data to the views render function (via events or whatever).

    the code: this.$el.find(‘ul’).append(li);
    can be written as
    this.$(‘ul’).append(li); 

    finally, your template doesn’t seem like a template, and it’s probably better practice to give the template to the view’s constructor.

    other than that, looks pretty good.
    hope to see you post a video focusing on event handling

    • http://www.joezimjs.com Joe Zimmerman

       Views have access to their models for a reason. In most implementations of MVC the view gets direct access to the model, or at least a portion of it as delegated by the controller, but since there isn’t really a controller, the view has to use the entire model. The model isn’t supposed to know which data the view uses and therefore shouldn’t be the one deciding what to send to the render function. In fact, models shouldn’t even know about the view. I think that I chose the best way to handle the relationship between the model and view.

      You’re definitely right about using this.$(‘ul’).append(li); I always forget about this.$

      The template isn’t a traditional template because it doesn’t have variables to replace, because, like I said in the video, I didn’t want to go into detail about templating. It’s still technically a template, I just replace empty spaces instead of variables. It would probably be a good idea to send the template in through the constructor, but since the view relies on this template following a specific structure (due to using straight jQuery rather than a templating library) I think a hard reference to the template within the view isn’t too horrible a choice. I definitely agree that it should probably be passed into the constructor in normal templating situations, though.

      I don’t have any videos planned to focus on event handling within Backbone.js. Their event handling system is rather simple, though I’ll try to make sure to go into some more details on event handling when I make videos on building the application.

      Thanks for taking the time to make your voice heard =)

  • http://rishabhsrao.github.com/ Rishabh Rao

    Hi Joe, your tutorials are great. Very easy to understand compared to the various other tutorials out there. Thank you very much. Looking forward to more awesome tutorials from you.

  • Ruf Dymond

    Hi Joe. I couldn’t get this exercise to conclude properly until I changed line 22 to be:

    $(this.el).find(‘ul’).append(li);

    I tried, this.$el, and when I viewed it in the debugger, it just kept stating that it was undefined. I even copied and pasted your text code above and it still wouldn’t work! Obviously, el, on it’s own is just a String too. It just prints out as #container.

    The only other way I could get it to work was to set el as a jQuery object:

    el: $(‘#container’)

    And then use:

    this.el.find(‘ul’).append(li);

    Do you have any ideas on why your version didn’t work for me?

    • http://www.joezimjs.com Joe Zimmerman

      My only guess is that you’re using an older version of Backbone that didn’t include the shortcut.

      BTW, as a note, this.$(‘ul’) should work as well. this.$ is a shortcut meaning $(‘SELECTOR’, this.el). In otherwords it is a standard jQuery lookup that uses this.el as the context for the query.

      • Ruf Dymond

        Thanks Joe. You were right! The problem turned out to be older versions of “underscore.js” AND “backbone.js”. I realised this by swapping each library in turn, but found out it was actually both of them.

        I was using v1.1.6 of “underscore.js”, and v0.3.3 of “backbone.js”.

        This is one of things that I dislike about using some JavaScript libraries. If you change them, your stuff can suddenly stop working, and it isn’t to determine why. I’ve had this in the past.

        Thanks for your help. Now, I’ll continue to work through the rest of the tutorials with the latest libraries!

        • http://www.joezimjs.com Joe Zimmerman

          I’m glad I could help.

  • JesseBreuer

    Could have been simpler using underscore.

    • http://www.joezimjs.com Joe Zimmerman

      I realize that, but I wanted to use something that I was sure the majority of readers would know about instead of possibly having to teach Underscore at the same time.

  • Daniel Moffat

    Should models hold groups of data like that? Or is this just a proof of concept?

    I was under the impression that each Model was a piece of data, in this example it would be each Model holds a link (with ‘href’ and ‘name’ attributes), and that the Collection would hold all of these Models.

    Excuse me if this sounds dumb – I’m trying to get my head around it all, after having read a bit about Backbone before coming here.

    Great tutorials by the way :)

    • http://www.joezimjs.com Joe Zimmerman

      This was definitely more of a proof of concept. It would definitely be more “correct” to have a collection hold several models each containing a single link. That is best practice, but of course, you are free to do it however you wish.

  • Maddy

    Hi Joe,

    i want to ask one question?

    i copied you code and trying to execute same code but while running program when i pressed load button event is not firing so pls give me solution.

    Thanks

    • Maddy

      i used 0.9.9 version of backbone.js and 1.3.3 of underscore.js

      • http://www.joezimjs.com Joe Zimmerman

        I just tried copying and pasting my code directly. The only thing I changed was the references to the Backbone and Underscore scripts so I could match the versions you are using. Everything is working just fine. The only thing I can think of is that you’re using a really old version of jQuery (if you use the code in the example, you’ll get 1.7.2) or there was an error when copying the code.

  • http://www.facebook.com/zimmer.joerg Jörg Zimmer

    What is the exact difference between

    this.el.find(‘ul’).append(li); and
    this.$el.find(‘ul’).append(li);

    From what I read (link below), I would prefer
    this.el.find(‘ul’).append(li);
    as the fastest method better than the more readable
    this.$(‘ul’).append(li);
    You have any comments an this Joe?
    http://24ways.org/2011/your-jquery-now-with-less-suck/

    • http://www.joezimjs.com Joe Zimmerman

      this.el is not a jQuery object. It is the DOM node.

      this.$el is the jQuery object wrapping that DOM node.

      this.$(‘ul’) is equivalent to $(‘ul’, ‘#container’);
      this.$el.find(‘ul’) is equivalent to $(‘#container’).find(‘ul’);

      They are essentially the same. The both search for #container and use that as the context for finding ul. In both cases with Backbone the search for ‘#container’ is already cached too. I did a quick speed test (just looped it 100,000 times and after all of those iterations this.$el.find(‘ul’) was around 50ms faster. Not at all worth fighting over. You can use whichever method you prefer, they are both optimized by having a the container cached and only searching within that context.

      The article you read didn’t mention the $(‘ul’, ‘#container’) way of doing it, but like I said, it is essentially the same as $(‘#container’).find(‘ul’).