“如何”在Backbone.js保存整个集合 – Backbone.sync或jQuery.ajax?

我很清楚它可以完成,我已经看了不less地方(包括: 保存整个集合的最佳实践? )。 但是我仍然不清楚在代码中是怎么写的? (这个post用英文解释,有一个javascript特定的解释会很棒:)

说我有一个模型集合 – 模型本身可能有嵌套的集合。 我已经重写父集合的toJSON()方法,我得到一个有效的JSON对象。 我希望“保存”整个集合(相应的JSON),但是主干似乎并没有内置这个function。

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

我知道你必须说的地方:

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

一旦处理完成“视图”,它就负责告知集合在服务器上“保存”自己(能够处理批量更新/创build请求)。

出现的问题:

  1. 如何在代码中编写“将所有东西连接在一起”?
  2. 什么是callback的“正确”位置以及如何指定“成功/错误”callback? 我的意思是语法?我不清楚在骨干中注册callback的语法…

如果这确实是一个棘手的工作,那么我们可以在视图中调用jQuery.ajax,并将this.successMethodthis.errorMethod作为成功/错误callback函数传递 它会起作用吗?

我需要与骨干的思维方式保持同步 – 我知道我肯定错过了一些东西,同步整个集合。

我的直接思想是不重写Backbone.Collection上的保存方法的方法,但将集合包装在另一个Backbone.Model并重写toJSON方法。 那么Backbone.js会把这个模型看作一个单一的资源,而且你不需要像backone一样思考太多。

请注意,Backbone.Collection有一个toJSON方法,所以你的大部分工作都是为你完成的。 您只需将您的包装Backbone.Model的toJSON方法代理到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 } }); 

一个非常简单的…

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

…会给你的collections一个保存方法。 请记住,这将始终将所有集合的模型发布到服务器,无论发生了什么变化。 选项只是普通的jQuery ajax选项。

我最终只是有一个“保存”的方法,并在其中调用$ .ajax。 它给了我更多的控制权,而不需要像@brandgonesurfingbuild议的那样添加一个包装类(尽pipe我绝对喜欢这个想法:)如前所述,因为我已经有了collection.toJSON()方法覆盖了我所有的所有使用它在阿贾克斯调用…

希望这可以帮助那些绊倒它的人

这真的取决于客户端和服务器之间的合同。 这里有一个简单的CoffeeScript示例,其中带有{"children":[{child1},{child2}]}的PUT to /parent/:parent_id/children将用PUT中的内容replace父项的子项并返回{"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.stringify(children: @toJSON())) response.done (models) => @reset models.children return response 

这是一个非常简单的例子,你可以做更多的事情……这实际上取决于执行save()时数据的状态,需要传送到服务器的状态以及服务器给出的内容背部。

如果你的服务器在[{child1},{child2]的PUT中可用,那么你的Backbone.sync行可能会变成response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json')

答案取决于你想要在服务器端收集什么。

如果您必须发送额外的数据 ,您可能需要包装模型或关系模型

使用包装器模型,您总是必须编写自己的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; } }); 

我认为关系模型更好,因为您可以更容易地configuration它们,并且可以使用includeInJSON选项来调节要放入您发送到rest服务的json的属性。

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

如果您不发送其他数据 ,则可以同步集合本身 。 在这种情况下,您必须将保存方法添加到您的集合(或集合原型)中:

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

我也很惊讶,Backbone集合没有内置的保存。 这就是我在我的骨干collections上做的。 我绝对不想迭代集合中的每个模型并独立保存。 另外,我使用Node在后台使用Backbone,所以我重写了原生的Backbone.sync以保存到我的小项目上的一个平面文件 – 但代码应该几乎相同:

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

老线我知道,我最终做的是以下几点:

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

相当紧张的前进:)

我会尝试像这样的:

 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/a/11085198/137067

这是一个简单的例子:

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

在集合上调用save()方法时,它会向定义的URL发送一个PUT方法请求。

接受的答案是相当不错的,但我可以更进一步,并给你代码,以确保正确的事件被激发为您的听众,同时也允许您传递选项ajax事件callback:

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

对于2017年仍在使用backbone.js的人来说,接受的答案是行不通的。

尝试去除包装模型中的toJSON()覆盖,并在实例化模型包装时调用集合上的JSON。

 new ModelWrapper(Collection.toJSON());