1

I have this model and a collection for it:

app.models.Result= Backbone.Model.extend({

    idAttribute: 'uid',

    initialize: function () {
        this.set('name', this.get('name').replace(' ', '').substring(0, 20));
    },

});

app.models.ResultList = Backbone.Collection.extend({

    model: app.models.Result,
    url: 'http://localhost/stuff',

    parse: function (response, options) {
        this.add(response.data);
        console.log(this);
        return response.data;
    },

});

Then I use it in my view's initialize() function like this:

var that = this;
this.collection = new app.models.SearchList();
this.collection.fetch({
    dataType: 'jsonp',
    success: function () {
        console.log(that.collection);
        that.collection.each(function (resultModel) {
            console.log('ok');
        });
    }
});

With this code I almost get what I want, but when I look at the second log() I can see that the name property is the same as it was in the fetched JSON.

First try's logs

My guess is because I simply returned the response.data, so I modified it to this. In this case I get an error:

Uncaught TypeError: Cannot call method 'replace' of undefined

So I commented out that line. Now I can see that all the models are gone. The array has only one model in it but that is not one from the JSON.

Second try's logs

What happend with my beloved models? Where are they? Should I save them somehow? At the first log this pointed to the correct full collection, so why doesn't returning this gives me the same correct collection.

totymedli
  • 29,531
  • 22
  • 131
  • 165

1 Answers1

2

You were correct when you were returning response.data from Collection.parse. To quote the documentation:

The function is passed the raw response object, and should return the array of model attributes to be added to the collection

I think your problem is that you're calling this.add from within Collection.parse - you don't need to do this, as the function that calls Collection.parse will deal with that for you.

I think what is happening when you do this is that the models are added when you call add, but then the Collection calls Collection.set - which causes all of the name values that you've modified to be replaced with the server versions.

To respond to your comment: Collection.set is called as part of Collection.fetch - that is just the way Backbone works by default (though you can have it call Collection.reset if you wish, by passing in an option). The easiest way to solve your problem would just be to remove the Collection.add call from your parse function - that way Collection.set will act as you expect.

The initialize function is just called on initialization of a model. If you want to change properties of models when they are first created that is one place to do it. However, you're creating the model by calling this.add, and then updating that data by returning data from parse - which causes the initialize changes to be overwritten.

Another way to do it would be to update your parse function to convert the data as needed, and then return that.

Alternatively you could override the set function in your Model to transform the data it is passed if the value being set is name

obmarg
  • 9,369
  • 36
  • 59
  • Thank for your response. I understand what are you talking about, but why does the `Collection.set` is called? What is more important: How can I solve the problem? How can I apply my changes to the `name` property in the model? I thought that the initialization function is the proper way. What is the purpose of the initialization if `set` overwrites what I have done there? – totymedli Nov 29 '13 at 00:00
  • @totymedli I've added a bit more detail with specific instructions on what to do. To put it simply: don't call `this.add` in `parse` – obmarg Nov 29 '13 at 00:13
  • Thank you very much! Now I totally understand the whole procedure and the suggestions you gave me made the code work like a charm! Thank you again. – totymedli Nov 29 '13 at 00:22