"How" to save the entire collection in Backbone.js - Backbone.sync or jQuery.ajax?

I am well aware that this can be done, and I have looked at quite a few places (including: Best practice for saving the entire collection? ). But I'm still not clear, โ€œhow is itโ€ written in code? (the post explains this in English. It would be great to have a specific javascript explanation :)

Let's say I have a set of models - the models themselves can have nested collections. I overridden the toJSON () method of the parent collection and I get a valid JSON object. I want to โ€œsaveโ€ the entire collection (corresponding to JSON), but the trunk does not seem to be built into this functionality.

var MyCollection = Backbone.Collection.extend({ model:MyModel, //something to save? save: function() { //what to write here? } }); 

I know somewhere you have to say:

 Backbone.sync = function(method, model, options){ /* * What goes in here?? If at all anything needs to be done? * Where to declare this in the program? And how is it called? */ } 

Once the โ€œbrowseโ€ is performed with processing, it is responsible for instructing the collection โ€œsaveโ€ itself on the server (capable of handling the bulk update / create request).

Questions that arise:

  • How / what to write in the code to "put it all together"?
  • What is the "correct" location of callbacks and how to indicate a success / error callback? I mean syntactically? I don't understand the syntax of registering callbacks in the trunk ...

If this is really a difficult task, then can we call jQuery.ajax in the view and pass this.successMethod or this.errorMethod as success / error callbacks? Will this work?

I need to synchronize with basic thinking - I know that I'm definitely missing something wrt, synchronization of entire collections.

+80
jquery ajax
Jul 29 '11 at 9:16 a.m.
source share
11 answers

My immediate thought is not to override the method of saving the method on Backbone.Collection, but to wrap the collection in another Backbone.Model and override the toJSON method. Then Backbone.js will consider the model as a single resource, and you will not have to crack the return path too much.

Note that Backbone.Collection has a toJSON method, so most of your work is done for you. You just need to proxy the toJSON method of your Backbone.Model wrapper to Backbone.collection.

 var MyCollectionWrapper = Backbone.Model.extend({ url: "/bulkupload", //something to save? toJSON: function() { return this.model.toJSON(); // where model is the collection class YOU defined above } }); 
+64
Jul 30 '11 at 20:35
source share

Very simple...

 Backbone.Collection.prototype.save = function (options) { Backbone.sync("create", this, options); }; 

... will give your collections a save method. Remember that this will always send all collection models to the server no matter what has changed. options are just plain jQuery ajax options.

+25
Apr 14 '13 at 22:17
source share

I ended up just using the save method and named $ .ajax inside it. This gave me more control over this without having to add a wrapper class as @brandgonesurfing suggested (although I really like the idea :) As mentioned, since I already had a collection.toJSON () method that was overridden, all I landed, used it in ajax call ...

Hope this helps someone who stumbles upon it ...

+8
Aug 6 2018-11-11T00:
source share

It really depends on what kind of contract is between the client and the server. Here's a simplified CoffeeScript example where PUT to /parent/:parent_id/children with {"children":[{child1},{child2}]} will replace the parent children with those in PUT and return {"children":[{child1},{child2}]} :

 class ChildElementCollection extends Backbone.Collection model: Backbone.Model initialize: -> @bind 'add', (model) -> model.set('parent_id', @parent.id) url: -> "#{@parent.url()}/children" # let say that @parent.url() == '/parent/1' save: -> response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON())) response.done (models) => @reset models.children return response 

This is a pretty simple example, you can do much more ... it really depends on what state your data is when you save (), in what state it should be sent to the server, and what the server returns.

If your server is OK with PUT [{child1},{child2] , your Backbone.sync line may change to response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json') .

+5
Mar 25 '12 at 22:05
source share

The answer depends on what you want to do with the server-side collection.

If you need to send additional data with a message, you may need a wrapper model or a relational model .

When using a wrapper model, you always need to write your own parse method:

 var Occupants = Backbone.Collection.extend({ model: Person }); var House = Backbone.Model.extend({ url: function (){ return "/house/"+this.id; }, parse: function(response){ response.occupants = new Occupants(response.occupants) return response; } }); 

Relational models are better, I think, because you can easily customize them and you can adjust using the includeInJSON parameter, which attributes are placed in json, which you send to the recreation service.

 var House = Backbone.RelationalModel.extend({ url: function (){ return "/house/"+this.id; }, relations: [ { type: Backbone.HasMany, key: 'occupants', relatedModel: Person, includeInJSON: ["id"], reverseRelation: { key: 'livesIn' } } ] }); 

If you do not send additional data , you can synchronize your own collection . You must add the save method to your collection (or prototype collection) in this case:

 var Occupants = Backbone.Collection.extend({ url: "/concrete-house/occupants", model: Person, save: function (options) { this.sync("update", this, options); } }); 
+5
May 31 '13 at 15:44
source share

I was also surprised that the Backbone collections do not have built-in storage. Here is what I put on my base collection to do this. I definitely don't want to iterate over each model in the collection and save it myself. Also, I use Backbone on the backend using Node, so I redefine my own Backbone.sync to save to a flat file on my small project, but the code should be something like this:

  save: function(){ Backbone.sync('save', this, { success: function(){ console.log('users saved!'); } }); } 
+3
Oct 18 '12 at 18:33
source share

Old thread, I know that I ended up doing the following:

 Backbone.Collection.prototype.save = function (options) { // create a tmp collection, with the changed models, and the url var tmpCollection = new Backbone.Collection( this.changed() ); tmpCollection.url = this.url; // sync Backbone.sync("create", tmpCollection, options); }; Backbone.Collection.prototype.changed = function (options) { // return only the changed models. return this.models.filter( function(m){ return m.hasChanged() }); }; // and sync the diffs. self.userCollection.save(); 

Pretty haunting limit :)

+3
Dec 24 '14 at 8:44
source share

I would try something like:

 var CollectionSync = function(method, model, [options]) { // do similar things to Backbone.sync } var MyCollection = Backbone.Collection.extend({ sync: CollectionSync, model: MyModel, getChanged: function() { // return a list of models that have changed by checking hasChanged() }, save: function(attributes, options) { // do similar things as Model.save } }); 

( https://stackoverflow.com ).

+1
Jun 18 2018-12-18T00:
source share

Here is a simple example:

 var Books = Backbone.Collection.extend({ model: Book, url: function() { return '/books/'; }, save: function(){ Backbone.sync('create', this, { success: function() { console.log('Saved!'); } }); } }); 

When you call the save () method in your collection, it sends a PUT method request to the specified URL.

+1
Mar 12 '15 at 12:55
source share

The accepted answer is pretty good, but I can take it one step further and give you code that will ensure that the proper events are fired for your listeners, as well as letting you go into the ajax callbacks:

 save: function( options ) { var self = this; var success = options.success; var error = options.error; var complete = options.complete; options.success = function( response, status, xhr ) { self.trigger('sync', self, response, options); if (success) return success.apply(this, arguments); }; options.error = function( response, status, xhr ) { self.trigger('error', self, response, options); if (error) return error.apply(this, arguments); }; options.complete = function( response, status, xhr ) { if (complete) return complete.apply(this, arguments); } Backbone.sync('create', this, options); } 
0
Jun 17 '16 at 17:14
source share

For those who still use backbone.js in 2017, the accepted answer does not work.

Try removing the toJSON () override in the wrapper model and calling jSON in the collection when creating the model instance.

 new ModelWrapper(Collection.toJSON()); 
0
Jan 13 '17 at 1:25
source share



All Articles