Updating a collection view when new collection is fetched
-
21-12-2019 - |
Question
I have a collection instance and then a collection view instance on page load that populates from the server a region and wineries from that region.
This is being called on my home page in a jQuery ready function...
var regionWineriesList = new RegionWineriesList();
var regionWineriesListView = new RegionWineriesListView({collection: regionWineriesList, map: Map.map});
regionWineriesList.fetch({
success: function(response) {
$('.wineries-scroll').prepend(regionWineriesListView.render().el);
}
});
This is working great.
I also have an autocomplete view that when clicked, does a fetch for a new set of data. It is in the findWineries() function.
var RegionsView = Backbone.View.extend({
el: 'body',
initialize: function(options) {
this.region_input = $('input#RegionLocation');
this.winery_input = $('input#WinerySearchHome');
},
events: {
'click input#RegionLocation': 'autoCompleteSetup',
'click .pulldown-arrow': 'autoCompleteSetup'
},
autoCompleteSetup: function() {
var self = this;
this.options = {minLength: 0, source: this.collection.toJSON()};
this.region_input.autocomplete(self.options);
this.region_input.autocomplete('search', '');
this.region_input.autocomplete({
select: function(event, ui) {
self.winery_input.val('Search By Winery Name');
self.findWineries(ui.item.label);
}
});
},
findWineries: function(label) {
var newRegionWineriesList = new RegionWineriesList();
newRegionWineriesList.fetch({
data: {region: label},
reset: true
});
}
});
This is also working in that it fetches the new data from the server.
I can't seem to figure out how to update the view once the new data is retrieved. I tried to bind the collection view to the collection but nothing is happening.
Here's the model, collection and collection view. I am leaving out the model view. Please advise if I need that and I will edit.
var RegionWinery = Backbone.Model.extend();
var RegionWineriesList = Backbone.Collection.extend({
model: RegionWinery,
url: '/regions/regions_wineries.json',
parse: function(response){
return response.wineries;
}
});
var RegionWineriesListView = Backbone.View.extend({
className: 'wineries',
initialize: function(options) {
_.bindAll(this, 'render');
this.listenTo(this.collection, 'reset', this.render);
this.map = options.map;
this.render();
},
render: function() {
this.collection.each(function(winery) {
var marker_view = new MapMarkerView({model: winery, map: this.map });
var regionWineriesView = new RegionWineriesView({model: winery, marker_view: marker_view});
this.$el.append(regionWineriesView.render().el);
}, this);
return this;
}
});
Solution
Normally the view would look more like this:
var RegionsView = Backbone.View.extend({
//...
findWineries: function(label) {
this.collection.fetch({
data: {region: label},
reset: true
});
}
});
then whatever creates that would create the regional list and whatever else cared would listen to the same collection:
var newRegionWineriesList = new RegionWineriesList();
var v = new RegionsView({ collection: newRegionWineriesList });
someOtherView.listenTo(newRegionWineriesList, 'reset', something_that_handles_the_reset);
A better way would be to set up a global event bus:
window.yourApp = window.yourApp || { };
yourApp.events = _({}).extend(Backbone.Events);
Then whatever it is that wants to know about a region change could listen to the global event bus:
this.listenTo(yourApp.events, 'new-region', function(region) {
// deal with the new region, this would usually be a method
});
and your RegionsView
could broadcast the new region with a trigger
call:
this.region_input.autocomplete({
select: function(event, ui) {
self.winery_input.val('Search By Winery Name');
yourApp.events.trigger('new-region', ui.item.label);
}
});
One nice advantage of this approach is that it is easy to have several things listening for the region change without having to tightly couple everything.