Disons que j'ai une collection et que j'ai apporté des modifications à plusieurs de ses modèles. Quelle est la meilleure façon d'enregistrer toutes les modifications en utilisant une seule requête HTTP ?
Réponses
Trop de publicités?Habituellement, les backends REST gèrent la création et la mise à jour d'une seule instance. Vous devez changer cela pour accepter un tableau d'objets.
Cela dit, du côté client, il faut aller directement à la fonction Backbone.sync.
Backbone.sync = function(method, model, options)
Dans ce cas, votre modèle doit être un tableau de modèles. La méthode doit être "create" ou "save" et les options prennent le même type d'options qu'un appel jQuery ajax (erreur, succès, etc.).
Je vais faire la mauvaise chose ici et citer Wikipedia en ce qui concerne pratiques RESTful appropriées : a PUT à example.com/resources
devrait remplacer la collection entière par une autre collection. Sur cette base, lorsque nous avons dû prendre en charge l'édition de plusieurs éléments simultanément, nous avons rédigé ce contrat.
- Le client envoie
{"resources": [{resource1},{resource2}]}
- Le serveur remplace l'ensemble de la collection par les nouvelles informations du client et renvoie les informations une fois qu'elles ont été persistées :
{"resources": [{"id":1,...},{"id":2,...}]}
Nous avons écrit la moitié serveur du contrat en Rails, mais voici la moitié client (en CoffeeScript, désolé !) :
class ChildElementCollection extends Backbone.Collection
initialize: ->
@bind 'add', (model) -> model.set('parent_id', .id)
url: -> "#{.url()}/resources" # let's say that .url() == '/parent/1'
save: ->
response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON()))
response.done (models) => @reset models.resources
Je pensais que c'était un lot plus facile à mettre en œuvre que de surcharger Backbone.sync. Un commentaire sur le code, nos collections ont toujours été des objets enfants, ce qui devrait expliquer pourquoi le code définit un "parent_id" chaque fois qu'un objet est ajouté à la collection, et comment la racine de l'URL est l'URL du parent. Si vous avez des collections au niveau de la racine que vous souhaitez modifier, il suffit de supprimer l'attribut des affaires.
Vous devez étendre Backbone.Collection
en lui donnant un save()
qui vérifierait chacun de ses modèles hasChanged()
.
Ensuite, il devrait appeler Backbone.sync
que vous devrez probablement étendre un peu dans une fonction de synchronisation personnalisée. Si vous utilisez une fonction de Backbone.sync
et assurez-vous de la définir dans votre collection.
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
}
});
Une approche différente (utilisant un modèle pour représenter la collection) est ici : "Comment" sauvegarder une collection entière dans Backbone.js - Backbone.sync ou jQuery.ajax ?
J'aime aussi https://stackoverflow.com/a/7986982/137067
Ce code ajoute une nouvelle méthode au prototype de collection pour appeler la méthode de sauvegarde des modèles qui ont été modifiés. Cela a fonctionné pour moi :
Backbone.Collection.prototype.saveAll = function(options) {
return $.when.apply($, _.map(this.models, function(m) {
return m.hasChanged() ? m.save(null, options).then(_.identity) : m;
}));
};
Lien vers le résumé : https://gist.github.com/julianitor/701c677279bac1529b88