Reputation: 63599
When a fetch
is called (in response to a user's action) after an initial fetch
, many of the newly fetched models can be similar to the existing models from the initial fetch
. If I call fetch
with the add: true
option, there can be duplicate models in the collection.
Problem: Instead of removing all existing models (say with id=1,2,3,4
) from the collection and inserting the newly fetched models (id=1,2,3,5
), is it possible to do the following 2 operations:
Add only the new models id=5
, resulting in a collection with id=1,2,3,4,5
. Then render only the new Views (id=5
)
Add the new models id=5
and remove the models not found in the new fetch
(id=4
). Then render the new Views (id=5
) and remove the old Views (id=4
)
Attempt:
Instead of calling App.listingCollection.fetch()
, the fetchNew()
function is used. This works to only add the new models id=5
to the collection.
How should the rendering of the new views only (id=5
) be triggered without re-rendering the existing views id=1,2,3,4
? I tried this with the line new ListingMarkerView({ model:item }).render();
within ListingCollection
, but I get an error responding to the line var marker = L.marker([this.model.get('lat'), this.model.get('lng')]);
in ListingMarkerView
:
Error
Uncaught TypeError: Object #<Object> has no method 'get'
Collection
ListingCollection = Backbone.Collection.extend({
model: Listing,
url: '/api/search_by_bounds',
fetchNew: function(options) {
options = options || {};
var collection = this,
success = options.success;
options.success = function(resp, status, xhr) {
_(collection.parse(resp, xhr)).each(function(item) {
// added this conditional block
if (!collection.get(item.id)) {
collection.add(item, {silent:true});
new ListingMarkerView({ model:item }).render();
}
});
if (!options.silent) {
collection.trigger('reset', collection, options);
}
if (success) success(collection, resp);
};
return (this.sync || Backbone.sync).call(this, 'read', this, options);
}
});
View
ListingMarkerView = Backbone.View.extend({
render: function() {
var marker = L.marker([this.model.get('lat'), this.model.get('lng')]);
markers.addLayer(marker);
},
close: function() {
this.unbind;
}
});
Upvotes: 1
Views: 4360
Reputation: 22728
A restful API has no concept of state of the clients it's speaking to, therefore when making a GET
request to retrieve a list of objects (e.g. http://example.com/restapi/user/), the rest server should ALWAYS return a full list of the matching objects.
On the Backbone end, you should then just .reset
your collection with the list from the server. .reset
will empty the collection and then add all the items, like:
my_collection.fetch({success: function(collection, resp){
collection.reset(resp, {silent: true});
}});
This way you don't get collisions and you don't have to worry about anything. Except if you've got models you've changed in the collection locally that haven't been saved back to the server.
If you're looking for a way to prevent modification of local items within a collection, that will need something like the sorcery you're speaking of above.
Upvotes: 3