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

时间:2011-07-29 21:16:24

标签: jquery ajax backbone.js

我很清楚它可以完成,我看了很多地方(包括:Best practice for saving an entire collection?)。但我仍然不清楚它在代码中写的“究竟是怎么样的”? (这篇文章用英文解释。有一个特定于javascript的解释很棒:)。

假设我有一组模型 - 模型本身可能有嵌套集合。我已经覆盖了父集合的toJSON()方法,我得到了一个有效的JSON对象。我希望“保存”整个集合(相应的JSON),但是主干似乎没有内置该功能。

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

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

出现的问题:

  1. 如何/在代码中写什么来“将它们连在一起”?
  2. 回调的“正确”位置是什么以及如何指定“成功/错误”回调?我的意思是语法上的?我不清楚在骨干网中注册回调的语法......
  3. 如果它确实是一个棘手的工作,那么我们可以在一个视图中调用jQuery.ajax并传递this.successMethodthis.errorMethod作为成功/错误回调??它会起作用吗?

    我需要与骨干的思维方式保持同步 - 我知道我肯定错过了w.r.t.,同步整个系列。

11 个答案:

答案 0 :(得分:64)

我的想法是不要覆盖Backbone.Collection上的save方法上的方法,而是将该集合包装在另一个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
 }

});

答案 1 :(得分:25)

非常简单......

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

...将为您的馆藏提供一种保存方法。请记住,无论发生什么变化,都会将所有集合的模型发布到服务器。选项只是普通的jQuery ajax选项。

答案 2 :(得分:8)

我最终只是采用了'save'方法,并在其中调用了$ .ajax。它给了我更多的控制权,而不需要添加一个包装类,如@brandgonesurfing建议的那样(虽然我非常喜欢这个主意:)正如我所说的那样,因为我已经重写了collection.toJSON()方法,所以我所做的就是使用它在ajax电话中......

希望这可以帮助那些偶然发现它的人......

答案 3 :(得分:5)

这实际上取决于客户端和服务器之间的合同。这是一个简化的CoffeeScript示例,其中/parent/:parent_id/children{"children":[{child1},{child2}]}的PUT将用PUT中的内容替换父项的子项并返回{"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()时的状态,它需要进入服务器的状态,以及服务器回馈。

如果您的服务器的PUT为[{child1},{child2],那么您的Backbone.sync行可能会更改为response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json')

答案 4 :(得分:5)

答案取决于您想要对服务器端的集合做什么。

如果您必须使用帖子发送其他数据,则可能需要包装模型或关系模型

使用包装模型,您始终必须编写自己的解析方法:

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 更好,因为您可以更轻松地配置,并且您可以使用includeInJSON选项来规范哪些属性要放入你发送到休息服务的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);
    }
});

答案 5 :(得分:3)

我也很惊讶Backbone收藏没有内置保存。这是我在我的骨干系列上做的事情。我绝对不想遍历集合中的每个模型并独立保存。另外,我在后端使用Node使用Backbone,所以我覆盖了本地Backbone.sync以保存到我的小项目中的平面文件 - 但代码应该是相同的:

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

答案 6 :(得分:3)

旧线程我知道,我最终做的是以下内容:

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

漂亮的紧张前行:)

答案 7 :(得分:2)

这是一个简单的例子:

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方法请求。

答案 8 :(得分:1)

我会尝试类似的事情:

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

答案 9 :(得分:1)

接受的答案非常好,但我可以更进一步,为您提供代码,确保为您的侦听器触发正确的事件,同时还允许您传入选项ajax事件回调:

print(service.translations().list(source='zh',
                                  target='en',
                                  q=['上海熙缘节能环保科技服务有限公司',
                                     '广东宏德科技物业有限公司']).execute())

if __name__ == '__main__':
    main()

答案 10 :(得分:0)

对于2017年仍在使用backbone.js的任何人,接受的答案都无效。

在实例化模型包装器时,尝试删除包装器模型中的toJSON()重写并在集合上调用toJSON。

new ModelWrapper(Collection.toJSON());