开发者

backbone.js - collections and views

I understand how to get a collection together, or an individual model. And I can usually get a model's data to display. But I'm not clear at all how to take a collection and get the list of models within that collecti开发者_如何学编程on to display.

Am I supposed to iterate over the collection and render each model individually? Is that supposed to be part of the collection's render function?

Or does the collection just have it's own view and somehow I populate the entire collection data into a view?

Just speaking generally, what is the normal method to display a list of models?


From my experience, it's the best to keep in your collection view references to each model's view.

This snippet from the project I'm currently working on should help you get the idea better:

var MyElementsViewClass = Backbone.View.extend({
    tagName: 'table',

    events: {
        // only whole collection events (like table sorting)
        // each child view has it's own events
    },
    initialize: function() {
        this._MyElementViews = {}; // view chache for further reuse
        _(this).bindAll('add');
        this.collection.bind('add', this.add);
    },
    render: function() {
        // some collection rendering related stuff
        // like appending <table> or <ul> elements

        return this;
    },
    add: function(m) {
        var MyElementView = new MyElementViewClass({
            model: m
        });

        // cache the view
        this._MyElementViews[m.get('id')] = MyElementView;

        // single model rendering
        // like appending <tr> or <li> elements
        MyElementView.render(); 
    }
});

Taking this approach allows you to update views more efficiently (re-rendering one row in the table instead of the whole table).


I think there are two ways to do it.

  • Use a view per item, and manipulate the DOM yourself. This is what the Todos example does. It's a nice way to do things because the event handling for a single model item is clearer. You also can do one template per item. On the downside, you don't have a single template for the collection view as a whole.
  • Use a view for the whole collection. The main advantage here is that you can do more manipulation in your templates. The downside is that you don't have a template per item, so if you've got a heterogeneous collection, you need to switch in the collection view template code -- bletcherous.

For the second strategy, I've done code that works something like this:

var Goose = Backbone.Model.extend({ });

var Gaggle = Backbone.Collection.extend({
   model: Goose;
};

var GaggleView = Backbone.View.extend({
    el: $('#gaggle'),
    template: _.template($('#gaggle-template').html()),
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
    }
};

var g = new Gaggle({id: 69);

g.fetch({success: function(g, response) {
    gv = new GaggleView({model: g});
    gv.render();
}});

The template code would look something like this:

  <script type="text/template" id="gaggle-template">
  <ul id="gaggle-list">
  <% _.each(gaggle, function(goose) { %>
     <li><%- goose.name %></li>
  <% }); %>
  </ul>
  </script>

Note that I use the _ functions (useful!) in the template. I also use the "obj" element, which is captured in the template function. It's probably cheating a bit; passing in {gaggle: [...]} might be nicer, and less dependent on the implementation.

I think when it comes down to it the answer is "There are two ways to do it, and neither one is that great."


The idea of backbone is that view rendering is event driven.

Views attach to Model data change events so that when any data in the model changes the view updates itself for you.

What you're meant to do with collections is manipulate a collection of models at the same time.

I would recommend reading the annotated example.


I've also found this a confusing part of the Backbone framework.

The example Todos code is an example here. It uses 4 classes:

  • Todo (extends Backbone.Model). This represents a single item to be todone.
  • TodoList (extends Backbone.Collection). Its "model" property is the Todo class.
  • TodoView (extends Backbone.View). Its tagName is "li". It uses a template to render a single Todo.
  • AppView (extends Backbone.View). Its element is the "#todoapp" . Instead of having a "model" property, it uses a global TodoList named "Todos" (it's not clear why...). It binds to the important change events on Todos, and when there's a change, it either adds a single TodoView, or loops through all the Todo instances, adding one TodoView at a time. It doesn't have a single template for rendering; it lets each TodoView render itself, and it has a separate template for rendering the stats area.

It's not really the world's best example for first review. In particular, it doesn't use the Router class to route URLs, nor does it map the model classes to REST resources.

But it seems like the "best practice" might be to keep a view for each member of the collection, and manipulate the DOM elements created by those views directly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜