Backbone.js upsert collection?

I am building an application with Backbone.js. Some of my server-side APIs will return me all new or changed models from a certain time. Some of these objects may be new to my collection, so I can just add them. Others may already exist, in which case I would like to update an existing model. So basically I'm looking for upsert (update-or-insert) functionality.

This is similar to the {add: true} parameter added in 0.9.0, except that I also want to update.

Is there a simple / known way to do this? It’s not difficult for me to update the code, but I don’t want to reinvent the wheel.

+6
source share
2 answers

NOTE. This answer was written for Backbone v0.9. Backbone v1.0 has since been released, which contains the collection.set() method described here . This will probably be the best solution.

I put together my own version of this on the weekend. I will post it here if anyone else finds this topic, but I will still be happy to see any other solutions that may be there.

I did this by changing the source of Backbone.js, which is not necessarily a great idea, but it was easy. There were two changes: first add this function to the Backbone.Collection prototype:

 //**upsert** takes models and does an update-or-insert operation on them //So models that already exist are updated, and new models are added upsert: function (models, options) { var self = this; options || (options = {}); models = _.isArray(models) ? models.slice() : [models]; var addModels = []; _.each(models, function (newModel) { var n = self._prepareModel(newModel, options); var existingModel = self.get(n.id); if (existingModel) { existingModel.set(n, options); } else { addModels.push(n); } }); if (!_.isEmpty(addModels)) { self.add(addModels, options); } } 

Then change one line in the Backbone.Collection.fetch () function to read:

 collection[options.add ? 'add' : (options.upsert ? "upsert" : 'reset')](collection.parse(resp, xhr), options); 

This allows you to call fetch({upsert:true}) to get the behavior I was looking for.

+3
source

I solved this situation in a general method:

 App.Utils = { refreshCollection: function( collection, collectionJSON ){ // update/add _( collectionJSON ).each( function( modelJSON ) { var model = collection.get( modelJSON.id ); if( model ) { model.set( modelJSON ); } else { collection.add( modelJSON ); } }); // remove var model_ids_to_keep = _( collectionJSON ).pluck( "id" ); var model_ids = collection.pluck( "id" ); var model_ids_to_remove = _( model_ids ).difference( model_ids_to_keep ) _( model_ids_to_remove ).each( function( model_id_to_remove ){ collection.remove( model_id_to_remove ); }); }, } 

Params

  • collection : this is Backbone.Collection
  • collectionJSON : this is an array with hash-style model data. typical JSON response.

I am sure that it can be optimized, especially the deleted part. But I keep it that way to read, because I'm still doing tests.

Usage example

 // code simplified and no tested var VolatileCollection = Backbone.Collection.extend({ // url: // model: // so on ... }) var PersistentCollection = Backbone.Collection.extend({ // url: not needed due this Collection is never synchronized or changed by its own // change the VolatileCollection instead, all changes will be mirrored to this Collection // through events // model: the same initialize: function( opts ){ this.volatileCollection = opts.volatileCollection; this.volatileCollection.on( "reset", this.update, this ); this.volatileCollection.on( "change", this.update, this ); } update: function(){ App.Utils.refreshCollection( this, this.volatileCollection.toJSON() ); } }) var volatileCollection = new VolatileCollection(); var persistentCollection = new PersistentCollection({ volatileCollection: volatileCollection }); volatileCollection.fetch(); 
+5
source

Source: https://habr.com/ru/post/910370/


All Articles