Handlebars won't loop over my Backbone.js Collection

I have a Backbone app where I'm attempting to populate a collection using a JSON file. I want to generate a list of "titles" from the JSON to eventually turn into a menu. Everything is going well, except that Handlebars won't loop (each) over my collection to render the list.

The relevant view:

var MenuView = Backbone.View.extend({

template: Handlebars.compile(
    '<ul>' +  
    '{{#each items.models}}<li>{{attributes.title}}</li>{{/each}}' +
    '</ul>'
),

initialize: function  () {
    this.listenTo(this.collection, "reset", this.render);
},   

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

});

The model and collection:

var Magazine = Backbone.Model.extend({
urlRoot:"/items",
defaults: {
    id: '',
    title: '',
    pubDate: '1/1',
    image: ''
}
});
var MagazineMenu= Backbone.Collection.extend({
    comparator: 'title',
    model: Magazine,
    url: "/items"
});

The router:

var MagazineRouter = Backbone.Router.extend({
routes: {
   "" : "listPage",
   "titles/:id" : "showTitle"
}, 
initialize: function  () {
    this.magazineModel = new Magazine();
    this.magazineModel.fetch();


    this.magazineView = new MagazineView({
        model: this.magazineModel
    });

    this.magazineCollection = new MagazineMenu();
    this.magazineCollection.fetch();

    this.menuView = new MenuView({collection: this.magazineCollection});
},

showTitle: function(id) {

    this.magazineModel.set("id", id);
    $("#theList").html(this.magazineView.render().el);
},

listPage : function() {
    $('#theList').html(this.menuView.render().el);
}
});

var router = new MagazineRouter();

$(document).ready(function() {
    Backbone.history.start(); 
});

And finally the JSON:

[
{
    "id": "screamingzebras",
    "url": "screamingzebras",
    "title": "Screaming Zebras",
    "pubDate": "2/1",
    "image": "screamingzebras.jpg"
},
{
    "id": "carousellovers",
    "url": "carousellovers",
    "title": "Carousel Lovers",
    "pubDate": "3/1",
    "image": "carousellovers.jpg"
},
{
    "id": "gardenstatuary",
    "url": "gardenstatuary",
    "title": "Garden Statuary",
    "pubDate": "4/1",
    "image": "gardenstatuary.jpg"
},
{
    "id": "sombreromonthly",
    "url": "sombreromonthly",
    "title": "Sombrero Monthly",
    "pubDate": "1/1",
    "image": "sombreromonthly.jpg"
}
]

When I run this in a browser, I get no errors in the console. If I console.log(this.collection) just before the call to this.$el.html(this.template(items)); in the view, I can see the collection with a models attribute that is properly populated from the JSON. When I look at the Elements panel in Chrome dev tools, I can see that it is generating everything up to and including the <ul> tag. That leads me to believe that I'm just missing a key logic point that is getting the Handlebars each function to actually loop over the collection.


I see two problems here:

  • items isn't defined anywhere so your render is really saying this.template(undefined) .
  • Even if you did have a local variable called items , your Handlebars template won't know that you've called it items so it won't know that {{#each items.models}} should iterator over it.
  • Presumably your items is really supposed to be the view's this.collection and your render should look more like this:

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

    That should solve problem 1 . You can fix problem 2 in two ways:

  • Change the template to refer to the right thing.
  • Change how you call this.template so that items is associated with the right thing.
  • The first option would use the above render and a template that looks like this:

    <ul>
        {{#each models}}
            <li>{{attributes.title}}</li>
        {{/each}}
    </ul>
    

    The second option would leave your template alone but change render to use:

    this.$el.html(
        this.template({
            items: this.collection
        })
    );
    

    Another option would be to use this.collection.toJSON() to supply data to the template, then render would use:

    this.$el.html(
        this.template({
            items: this.collection.toJSON()
        })
    );
    

    and then template would be:

    <ul>
        {{#each items}}
            <li>{{title}}</li>
        {{/each}}
    </ul>
    
    链接地址: http://www.djcxy.com/p/61592.html

    上一篇: 不要使用Ember / Handlebars中的#each来销毁DOM元素

    下一篇: 把手不会遍布我的Backbone.js集合