I've got a simple REST API that gives me data about an item at /api/items/:id
, including ID and name. I'm using a Router to organise my Backbone views. The edit
route instantiates a FormEditItem view, passing it the ID from the URL.
To get the data for the model from the API, the form view instantiates a new model, sets the ID and then calls the model's fetch method. (The second approach recommended in this thread.)
The model declaration is extremely simple:
App.Models.Item = Backbone.Model.extend({
urlRoot: 'api/items'
});
And this is my form view:
App.Views.FormEditItem = Backbone.View.extend({
template: _.template($('#tpl-formEditItem').html()),
initialize: function(opts) {
_.bindAll(this, "render");
this.modelID = opts.modelID;
this.parent = opts.parent;
this.model = new App.Models.Item({id: this.modelID});
this.model.fetch();
this.render();
},
render: function() {
console.log('Starting render:', this.model);
console.log(this.model.get('name'));
this.parent.$el.append(this.template(this.model.toJSON()));
return this;
}
});
In my form view's render function I'm logging out the model. I can see the model's attributes. But on the next line, when I try to log out the results of get('name'), I get undefined!
What's going on? Do I need to define a model's attributes before I try to fetch them from the database?
=============================================================================
EDIT
Following Stephen and Rida's advice, the fix in this situation is to add an event listener to the model's change
event. The fetch
operation takes some time to get the data from the API: I was trying to output the data before it arrived. So my initialize function should read:
initialize: function(opts) {
_.bindAll(this, "render");
this.modelID = opts.modelID;
this.parent = opts.parent;
this.model = new App.Models.Item({id: this.modelID});
this.listenTo(this.model, 'change', this.render);
this.model.fetch();
}
Thanks a lot guys!
The problem is that you're trying to render the view before the fetch completes. In initialize, you call
this.model.fetch()
and then immediately call
this.render()
At that point the fetch won't have completed, so there won't be a name
attribute.
When you look at the model in the console, that's after the fetch has completed, so then there is a name