«Comment» enregistrer une collection entière dans Backbone.js – Backbone.sync ou jQuery.ajax?

Je sais bien que cela peut être fait et j’ai examiné plusieurs endroits (y compris: Meilleures pratiques pour sauvegarder une collection entière? ). Mais je ne suis toujours pas clair “exactement comment” est-il écrit dans le code? (le post explique cela en anglais. Ce serait bien d’avoir une explication spécifique au javascript 🙂

Disons que j’ai une collection de modèles – les modèles eux-mêmes peuvent avoir des collections nestedes. J’ai remplacé la méthode toJSON () de la collection parent et j’obtiens un object JSON valide. Je souhaite “sauvegarder” la collection entière (JSON correspondant), mais le backbone ne semble pas être intégré à cette fonctionnalité.

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

Je sais que quelque part il faut dire:

 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? */ } 

Une fois que la vue est faite avec le traitement, il est chargé de dire à la collection de “sauvegarder” elle-même sur le serveur (capable de gérer une demande de mise à jour / création groupée).

Questions qui se posent:

  1. Comment / quoi écrire dans le code pour “câbler le tout”?
  2. Quel est le «bon» emplacement des rappels et comment spécifier un rappel «succès / erreur»? Je veux dire syntaxiquement? Je ne suis pas au courant de la syntaxe de l’enregistrement des rappels dans le backbone …

Si c’est un travail difficile, peut-on appeler jQuery.ajax dans une vue et passer le this.successMethod ou this.errorMethod tant que this.errorMethod succès / erreur? Est-ce que ça marchera?

Je dois être en phase avec la façon de penser de backbone – je sais que je manque définitivement quelque chose, la synchronisation de collections entières.

Ma pensée immédiate n’est pas de remplacer la méthode sur la méthode save sur Backbone.Collection, mais d’envelopper la collection dans un autre Backbone.Model et de remplacer la méthode toJSON à cet égard. Ensuite, Backbone.js traitera le modèle comme une ressource unique et vous n’aurez pas à pirater la façon dont backone pense trop.

Notez que Backbone.Collection a une méthode toJSON afin que la plupart de votre travail soit fait pour vous. Vous devez juste utiliser la méthode toJSON de votre wrapper Backbone.Model pour la collection Backbone.

 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 } }); 

Un très simple …

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

… donnera à vos collections une méthode de sauvegarde. Gardez à l’esprit que cela affichera toujours tous les modèles de la collection sur le serveur, indépendamment de ce qui a changé. les options ne sont que des options jQuery ajax normales.

J’ai fini par avoir une méthode de type “save” et j’ai appelé $ .ajax. Cela m’a donné plus de contrôle sans avoir besoin d’append une classe de wrapper comme @brandgonesurfing (bien que j’adore l’idée 🙂 Comme je l’ai déjà fait, la méthode collection.toJSON () a été écrasée. dans l’appel ajax …

J’espère que cela aidera quelqu’un qui trébuche sur elle …

Cela dépend vraiment du contrat entre le client et le serveur. Voici un exemple simplifié de CoffeeScript où un PUT à /parent/:parent_id/children avec {"children":[{child1},{child2}]} remplacera les enfants d’un parent par ce qui est dans PUT et 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's say that @parent.url() == '/parent/1' save: -> response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.ssortingngify(children: @toJSON())) response.done (models) => @reset models.children return response 

Ceci est un exemple assez simple, vous pouvez faire beaucoup plus … cela dépend vraiment de l’état de vos données lorsque save () est exécuté, de l’état dans lequel il doit être envoyé au serveur et de ce que le serveur donne arrière.

Si votre serveur est compatible avec un PUT de [{child1},{child2] , alors votre ligne Backbone.sync peut changer en response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json') .

La réponse dépend de ce que vous voulez faire avec la collection côté serveur.

Si vous devez envoyer des données supplémentaires avec le message, vous pouvez avoir besoin d’un modèle d’encapsuleur ou d’un modèle relationnel .

Avec le modèle wrapper, vous devez toujours écrire votre propre méthode d’ parsing :

 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; } }); 

Les modèles relationnels sont meilleurs, je pense, car vous pouvez les configurer plus facilement et vous pouvez régler avec l’option includeInJSON les atsortingbuts à mettre dans le json que vous envoyez à votre service de repos.

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

Si vous n’envoyez pas de données supplémentaires , vous pouvez synchroniser la collection elle-même . Vous devez append une méthode de sauvegarde à votre collection (ou au prototype de collection) dans ce cas:

 var Occupants = Backbone.Collection.extend({ url: "/concrete-house/occupants", model: Person, save: function (options) { this.sync("update", this, options); } }); 

J’ai été également surpris que les collections Backbone ne disposent pas d’une sauvegarde intégrée. Voici ce que je mets sur ma collection backbone pour le faire. Je ne veux certainement pas parcourir chaque modèle de la collection et enregistrer indépendamment. De plus, j’utilise Backbone sur le backend à l’aide de Node, donc je remplace le Backbone.sync natif pour enregistrer dans un fichier plat sur mon petit projet – mais le code devrait être pratiquement le même:

  save: function(){ Backbone.sync('save', this, { success: function(){ console.log('users saved!'); } }); } 

Vieux fil que je sais, ce que j’ai fini par faire est le suivant:

 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(); 

Joli avant-gardiste 🙂

Je voudrais essayer quelque chose comme:

 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(atsortingbutes, options) { // do similar things as Model.save } }); 

( https://stackoverflow.com/a/11085198/137067 )

Voici un exemple simple:

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

Lorsque vous appelez la méthode save () sur votre collection, elle envoie une demande de méthode PUT à l’URL définie.

La réponse acceptée est plutôt bonne, mais je peux aller plus loin et vous donner un code qui garantira que les événements appropriés sont déclenchés pour vos auditeurs tout en vous permettant de transmettre l’option callback d’événement ajax:

 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.sortinggger('sync', self, response, options); if (success) return success.apply(this, arguments); }; options.error = function( response, status, xhr ) { self.sortinggger('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); } 

Pour ceux qui utilisent encore backbone.js en 2017, la réponse acceptée ne fonctionne pas.

Essayez de supprimer le remplacement toJSON () dans le modèle wrapper et en appelant toJSON sur la collection lorsque vous instanciez le wrapper de modèle.

 new ModelWrapper(Collection.toJSON());