Reputation: 1598
I'm trying to do the following:
I was trying to do this by using a success callback in the collection
View Before
initialize: () ->
@collection.on 'reset', @render, this
render: () -> ...render code...
Collection Before
search: () ->
@fetch {
success: @fetch_success
}
fetch_success: () ->
for i in [0...collection.models.length]
collection.models[i].set('go_index', i)
Doing things this way was causing the views to fire their render events before the collection was updated by the success callback. The solution I came up with was to have the views listen to a fetched
event, then have the collection fire that after it successfully modifies the collection:
View After
initialize: () ->
@collection.on 'fetched', @render, this
render: () -> ...render code...
Collection After
initialize: () ->
@on 'reset', @add_index_and_notify, this
add_index_and_notify: () ->
for i in [[email protected]]
@models[i].set('go_index', i)
@trigger('fetched')
This works fine, I'm just wondering if this is the most elegant way to accomplish this or if there is a built-in way that I'm missing.
UPDATE 3/15
I've come up with a cleaner solution that doesn't require the view to do any of the dirty work and I don't have to create a custom event. The trick is to listen to the sync
event (which fires after reset
)
View Final
initialize: () ->
@collection.on 'sync', @render, this
render: () -> ...render code...
Collection Final
initialize: () ->
@on 'reset', @add_index, this
add_index: () ->
for i in [[email protected]]
@models[i].set('go_index', i)
Hopefully this pattern can help somebody searching in the future.
Upvotes: 1
Views: 893
Reputation: 146064
Your view should get both the model and it's index separately from the collection because the index isn't really part of the model record itself. Try having your view use collection.each
to loop over the models as the callback function there will get model, index, collection
as parameters. Remember a view can pass more than just a single model to its template.
class CollectionView1 extends Backbone.View
render: =>
$el = @$el
$el.empty()
@collection.each (model, index) ->
modelView = new ModelView1 {model, index}
$el.append modelView.render().el
return this
Upvotes: 1
Reputation: 1598
I've already posted the solution in the original question, but I figured I'd formally post as an answer:
The cleaner solution doesn't require the view to do any of the dirty work and doesn't require a custom event. The trick is to listen to the sync
event (which fires after reset
)
View Final
initialize: () ->
@collection.on 'sync', @render, this
render: () -> ...render code...
Collection Final
initialize: () ->
@on 'reset', @add_index, this
add_index: () ->
for i in [[email protected]]
@models[i].set('go_index', i)
Hopefully this pattern can help somebody searching in the future.
Upvotes: 3
Reputation: 55750
Why don't you listen to the add event of the collection..
initialize: function() {
this.listenTo(this.collection, 'reset', this.render);
this.listenTo(this.collection , 'add' , this.add_index_and_notify);
this.index = 0;
},
add_index_and_notify: function(model){
model.set({go_index : this.index++}, {silent : true});
// Render the model here
},
render: function(){
this.$el.empty().append(Your template);
this.index= 0;
_.each(this.collection.models, function(model){
this.add_index_and_notify(model);
}
}
Upvotes: 0