So i'm very new to backbone.js and not so good at JavaScript in general, so I was wondering if someone could explain to me why
I cannot define my EL property, and Template property in my view, and then use this.template in my render. Instead I have to define the template and el in my render function.
var ProductView = Backbone.View.extend({
el: $('#product-list'),
initialize: function() {
this.el.html('<span style="color:white">loading...</span>');
}, // end initialize
render: function(collection) {
// // assign the template
this.template = $('#product_template');
// Where the template will be placed
this.el = $('#product-list');
// Add the collection to the main object
this.collection = collection;
// add tthe data to the html variable
var html = this.template.tmpl(this.collection.toJSON());
// place the html in the element.
this.el.html(html);
// not even sure what the hell this is.
return this;
} // end render
});
So i'm very new to backbone.js and not so good at JavaScript in general, so I was wondering if someone could explain to me why
I cannot define my EL property, and Template property in my view, and then use this.template in my render. Instead I have to define the template and el in my render function.
var ProductView = Backbone.View.extend({
el: $('#product-list'),
initialize: function() {
this.el.html('<span style="color:white">loading...</span>');
}, // end initialize
render: function(collection) {
// // assign the template
this.template = $('#product_template');
// Where the template will be placed
this.el = $('#product-list');
// Add the collection to the main object
this.collection = collection;
// add tthe data to the html variable
var html = this.template.tmpl(this.collection.toJSON());
// place the html in the element.
this.el.html(html);
// not even sure what the hell this is.
return this;
} // end render
});
Share
Improve this question
edited Oct 26, 2011 at 21:12
mu is too short
435k71 gold badges858 silver badges818 bronze badges
asked Oct 26, 2011 at 19:32
GamakGamak
1993 silver badges12 bronze badges
5
-
You don't have to do this.
this.el
should be set by the timeinitialize
is called (but you should use$(this.el)
-el
is generally the DOM element, not a jQuery object). You can define the template ininitialize
if you prefer. Are you getting errors? – nrabinowitz Commented Oct 26, 2011 at 19:37 -
Also,
return this;
is a Backbone convention that allows chaining, e.g.$(parent).append(view.render().el)
- you can't use that last.el
in the same statement unless you return the view in.render()
. – nrabinowitz Commented Oct 26, 2011 at 19:39 - The code I have is working for me, but it doesnt look like anything i've seen in the tutorials, so i'm thinking i'm doing something wrong. – Gamak Commented Oct 26, 2011 at 20:53
- Right, but does it throw some kind of error if you do it the way I describe? – nrabinowitz Commented Oct 26, 2011 at 20:59
- I'm not getting an error when I do it your way, its just not rendering the collection. And if I do a console.log($(this.el)); inside the render function I get undefined – Gamak Commented Oct 26, 2011 at 21:17
2 Answers
Reset to default 7The problem isn't in the way you're defining el
or template
, it's in how you're setting the call back. In Workspace
, your router, you're setting the callback for your collection refresh event like this:
// Bind the view and collection
// So when the collection is reset, the view executes the render method
Products.bind("reset", this.view.render);
The problem is, you're setting a method as a callback, but you're not providing a context object as the third argument to bind - so the method is called, but this
in the method refers to the global object, not the view. So this.el
is undefined, because it's not looking at the view instance at all. Try:
// Bind the view and collection
// So when the collection is reset, the view executes the render method
Products.bind("reset", this.view.render, this.view);
and see how that goes.
(I made a jsFiddle to demonstrate that the el
and template
were set properly under normal circumstances, though it doesn't actually include the fix above, which is hard to mock up without the server-side data: http://jsfiddle/nrabinowitz/QjgS9/)
You can't do this:
var ProductView = Backbone.View.extend({
el: $('#product-list'),
// ...
and get anything useful in el
as #product-list
probably isn't even present in the DOM when your ProductView is built; so trying to use $('#product-list')
for el
is simply the classic "I forgot to use $(document).ready()
" problem dressed up in Backbone. Using $('#product-list')
for el
should work if #product-list
is around when you define your ProductView though.
You can do this though:
var ProductView = Backbone.View.extend({
el: '#product-list',
// ...
and then say $(this.el)
when you need to do things inside your view methods. Not only is $(this.el)
the usual way of using el
but it also works and that's sort of important.
The same issues apply to #product_template
.
Looking at your code I see this:
// INstantiate the view
this.view = new ProductView();
// Bind the view and collection
// So when the collection is reset, the view executes the render method
Products.bind("reset", this.view.render);
Presumably the render
is being triggered by the reset event. But, and this is a big but, the render
method isn't bound to the right this
anywhere so this
won't be the ProductView
when render
is called and this
won't have anything that you expected it to; hence your bizarre "undefined" error.
You could use _.bindAll
in your initialize
:
initialize: function() {
_.bindAll(this, 'render');
// ...
but usually you'd want to give the view a collection when you create it and the view would bind itself to the events so your structure will still be a bit odd.
You can also supply a context (AKA this
) when you call bind
:
collection.bind('reset', this.render, this);