Backbone.js | How can I store elements of a view for retrieval later?
This is my first attempt at using Backbone.js, so I decided to make a simple test application that simulates a restaurant menu with menu items. I was following along with this cool blog post from andyet.net.
I'm having a problem when adding a model to a collection. I have bound a view method to the collection's add event that should update the view. Here is the code with as much irrelevant code removed as possible.
(note: I removed things like local scope var
declarations and closures for the sake of brevity. The following is still a little long, and I know that's annoying, but it should be pretty straightforward and easy to understand):
MenuItem = Backbone.Model.extend({
// initialize functions removed for brevity
});
Menu = Backbone.Model.extend({
// initialize functions removed for brevity
// MenuSelection property is defined here.
});
MenuSelection = Backbone.Collection.extend({ model: MenuItem });
MenuItemView = Backbone.View.extend({
// render template
});
/**
* This is unaltered from the code. The error occurs here.
*/
RestaurantAppView = Backbone.View.extend({
addMenuItem : function (MenuItem) {
var view = new MenuItemView({ model : MenuItem });
this.menuList.append(view.render().el);
// ERROR occurs here. error: "this.menuList is undefined"
},
initialize : function () {
this.model.MenuSelection.bind('add', this.addMenuItem);
},
render : function () {
$(this.el).html(ich.app(this.model.toJSON()));
this.menuList = this.$('#menuList'); // IT IS DEFINED HERE
return this;
}
});
/**
* Everything after this I left in just-in-case you need to see it.
*/
RestaurantAppController = {
init : function (spec) {
this.config = { connect : true };
_.extend(this.config, spec);
this.model = new Menu({
name : this.config.name,
});
this.view = new RestaurantAppView({ model : this.model });
return this;
}
};
$(function() {
// simulating ajax JSON response.
var json = {
Menu : {
name : 'Appetizers',
MenuItem : [
{
name : 'toast',
description : 'very taosty',
price : '$20.00'
},
{
name : 'jam',
description : 'very jammy',
price : '$10.00'
},
{
name : 'butter',
description : 'very buttery',
price : '$26.00'
}
]
}
};
window.app = RestaurantAppController.init({
name : json.Menu.name
});
$('body').append(app.view.render().el);
app.model.MenuSelection.add(json.Menu.MenuItem);
});
I've marked with comments the problematic area. According the the Backbone Documentation:
If jQuery or Zepto is included on the page, each view has a $ function that runs queries scoped within the view's element.
So, if I'm setting this.menuList = this.$('#menuList');
in the render method, why can I not access this.menuList
in the addMenuItem
method? The demo I linked to at the top does it exacly like this. Also, if I swap out this.menuList
for a jQuery selector, like so:
addMenuItem : function (MenuItem) {
var view = new MenuItemView({ model : MenuItem });
$('#menuList').append(view.render().el);
}
Everything works fine. But I don't want to re-select the menulist ID every time addMenuItem
is executed. The RightWayTM is to cache it after it is rendered.
Also note: I thought maybe the probl开发者_开发问答em was with the ICanHaz template not returning fast enough, but then this.menuList
would be an empty array, not undefined
, so that's not it.
You're running into the #1 gotcha with JavaScript -- the dynamically scoped this
keyword. When you pull off this.addMenuItem
as a reference without binding it, the addMenuItem
function loses its notion of this
. There are two easy ways to fix it in your code, either replace this line:
this.model.MenuSelection.bind('add', this.addMenuItem);
With this:
this.model.MenuSelection.bind('add', _.bind(this.addMenuItem, this));
Or add this line to the top of your initialize function, which will accomplish effectively the same thing:
_.bindAll(this, 'addMenuItem');
Probably addMenuItem method is being called before render method is called and hence the definition for menuList is missing in the addMenuItem.
Why don't you push this.menuList = this.$('#menuList'); to initialize method and try?
精彩评论