1
votes

I'm having trouble with models disappearing after populating a Backbone collection from a url. The code works if I just pass the array into the collection.

The collection:

var CustomerList = Backbone.Collection.extend({
     model: Customer,
     url: "/customer_list/json"
});

the url returns:

[
   {
      "id":"870000",
      "name":"vitae odio",
      "contact_name1":"ame",
      "contact_number1":"345634565246",
      "contact_name2":"",
      "contact_number2":"",
      "address_line1":"Ap #489-8375 Ornare, Ave2",
      "address_line2":"",
      "town":"Stillwater",
      "county":"Herefordshire",
      "postcode":"JV5H 2QH",
      "email":"[email protected]",
      "created_at":"0000-00-00 00:00:00",
      "updated_at":"2012-08-18 16:44:36"
   },
   {
      "id":"870001",
      "name":"mauris, aliquam",
      "contact_name1":"Quail",
      "contact_number1":"82733186940",
      "contact_name2":null,
      "contact_number2":null,
      "address_line1":"Ap #921-368 Cras Ave",
      "address_line2":null,
      "town":"Lake Charles",
      "county":"Essex",
      "postcode":"AP6 0KZ",
      "email":"[email protected]",
      "created_at":"0000-00-00 00:00:00",
      "updated_at":"0000-00-00 00:00:00"
   }
]

The view:

$(function() {

/* Customer View */
var CustomerView = Backbone.View.extend({
    tagName: 'tr',
    className: 'customer-row',
    template: _.template($('#customerRowTemplate').html()),

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

/* Customer List View */
var CustomerListView = Backbone.View.extend({
    el: $('#customers'),

    initialize: function() {
        this.collection = new CustomerList();
        this.collection.bind('reset', this.render());
        this.collection.fetch();
    },

    render: function() {
        console.log(this.collection);
        console.log(this.collection.models);

        _.each(this.collection.models, function(customer) {
            this.renderCustomer(customer);
        }, this);
    },

    renderCustomer: function(customer) {
        var customerView = new CustomerView({
            model: customer
        });

        var html = customerView.render();

        this.$el.find('#customer-list').append(html);
    }
});

var customerList = new CustomerListView();

});

When calling console.log(this.collection); it shows the model array has a length of 366 and I can view all of the models in the inspector.

But when calling console.log(this.collection.models); it returns an empty array. Which means that the collection is not iterated over and therefore never rendered. Again this works fine if I just pass in the customer list manually.

Any help would be greatly appreciated.

2
You shouldn't put your whole application definition inside a $() ready callback... just leave your view instantiation in there.Cobby

2 Answers

1
votes

The problem is here: this.collection.bind('reset', this.render());

this.render() should be this.render. Using parentheses calls the function on the spot, before the collection has a chance to fetch the models.

You should also pass the context to the render function. This can be done in 2 ways:

  • Add _.bindAll(this, "render") to the CustomerListView initialize method.
  • this.collection.bind('reset', this.render, this) - add this as the third argument.

EDIT

For version 0.9.9 and above, use this.listenTo(this.collection, 'reset', this.render)

1
votes

You don't need to bind anything with Backbone. It is using undescore correctly under the hood. You are not correctly using the each method neither.

Furthermore, if you want to bind an action, you must use the function name, and not executing it :

this.collection.bind('reset', this.render);

instead of

 this.collection.bind('reset', this.render());

I would try also :

initialize: function() {
    this.collection = new CustomerList();
    this.collection.fetch();
},

render: function() {
    console.log(this.collection);
    console.log(this.collection.models);

    this.collection.each(function(customer) {
        this.renderCustomer(customer);
    });
}

What do you want exactly with 'reset' ? the bind function is NOT in the Backbone API. Did you meant 'on' ?