Reputation: 13400
I have no idea why this code is not working.
Reading the documentation,
the templateHelpers
should be called.
My goal is to pass the this.collection.length
to the template.
Any hints? thanks.
I am using Backbone.Marionette v0.9.5
return Marionette.CompositeView.extend({
className: 'user-board',
template: usersTemplate,
itemView: userItemView,
initialize: function () {
this.collection = new UseList();
this.collection.fetch();
},
appendHtml: function (collectionView, itemView) {
collectionView.$el.find('ul.users-list').append(itemView.el);
},
templateHelpers: function () {
console.log(this.collection.length);
},
serializeData: function () {
return {
weekly: this.options.weekly,
users_length: this.collection.length // here the length is zero
// after the fetch the length is > 0
// but in template remains 0
};
}
});
To fix my issue I have to make the following...
initialize: function () {
_.bindAll(this, 'render');
this.collection = new NewCollection();
this.collection.fetch({
success: this.render
});
}
Is there a better way to make it working?
Upvotes: 2
Views: 7452
Reputation: 346
After using a setup like has been detailed, you can also use template helpers a bit more usefully than has been described so far.
For example,
If you simply drop in <%= functionName %> into the template where you are trying to get the number to show up visually on the front end page (since you want .length I see), marionette will simply do the work for you.
So like this:
--Template File--
<div id="followerCount"> <%= showCount %> </div>
--Helper Function in View--
templateHelpers: {
showCount: function(){
return this.collection.length;
}
}
Hope that made sense or at least helps someone else perhaps looking for a simpler way to integrate database returned json to their templates.
Upvotes: 0
Reputation: 7017
At least in Marionette v1.0.3, I'm liking the pattern that rendering is handled automatically during a call to Region.show(), so I call that from a controller object which has the collection and passes it to the view on instantiation then shows the view. I don't even have to put this logic in a fetch success callback or explicitly bind to the 'reset' event, because the Marionette composite/collection view already knows to (re-)render itself on fetch success (which a debugger will show you).
Upvotes: 0
Reputation: 3040
This code only declares the a view. Can you share the code the instantiates the view and displays it? templateHelpers
will be called and the data passed to the template when the template is rendered. That is, you either need to show the view in a region which implicitly calls the render
method on the view, or explicitly call the render
method.
To be useful, templateHelpers
should return an object. For instance:
templateHelpers: function() {
return {colLength: this.collection.length};
}
One important thing to keep in mind: fetch
trigger an AJAX request that is done asynchronously. If you want to wait for the fetch
to succeed before rendering the view, then you need to use Marionette.Async.
Update based on the update question
To avoid calling render
from the view's initialize
and only do it when render
is called externally, change your code to:
return Marionette.CompositeView.extend({
className: 'user-board',
template: usersTemplate,
itemView: userItemView,
initialize: function () {
this.collection = new UseList();
var that = this;
this.defer = $.Deferred();
this.collection.fetch({
success: that.defer.resolve,
error: that.defer.resolve
});
},
appendHtml: function (collectionView, itemView) {
collectionView.$el.find('ul.users-list').append(itemView.el);
},
templateHelpers: function () {
console.log(this.collection.length);
// For greater flexibility and maintainability, don't override `serializeData`.
return {
weekly: this.options.weekly,
users_length: this.collection.length
};
},
render: function() {
var that = this,
args = arguments;
$.when(this.defer).done(function() {
Marionette.CompositeView.prototype.apply(that, args);
});
}
});
I'm resolving this.render
both on success and error, otherwise if there is an error the view will never render (unless that's what you want).
Note that if you use Marionette.Async then you would return this.defer
in the view's beforeRender
and Marionette.Async would take care of delaying the rendering.
Also note that once this.defer
is resolved, future renders will run when called as there is nothing to wait for, until this.defer
has been reset programmatically.
Upvotes: 1
Reputation: 1051
Reading the Marionette Documentation serializeData
method, which is the one using mixinTemplateHelpers
, is only called on Item View.render
method here and in your current code you do not render at all
UPDATE: This way everytime the collection receives new data it will update your view the new length
initialize: function () {
_.bindAll(this, 'render');
this.collection = new NewCollection();
this.collection.fetch();
this.collection.bind('reset', this.render);
}
Upvotes: 3