"Как" сохранить всю коллекцию в Backbone.js - Backbone.sync или jQuery.ajax?

Мне хорошо известно, что это можно сделать, и я просмотрел довольно много мест (в том числе: Лучшая практика для спасения всей коллекции?). Но я до сих пор не ясно, "как это" написано в коде? (сообщение объясняет это на английском языке. Было бы здорово иметь специфическое объяснение 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?
 */
}

Как только "просмотр" выполняется с обработкой, он отвечает за указание коллекции "сохранить" себя на сервере (способный обрабатывать массовое обновление/запрос создания).

Вопросы, которые возникают:

  • Как/что писать в коде, чтобы "соединить все это вместе"?
  • Какое "правильное" расположение обратных вызовов и как указать обратный вызов "успех/ошибка"? Я имею в виду синтаксически? Я не понимаю синтаксиса регистрации обратных вызовов в магистрали...

Если это действительно сложная задача, тогда мы можем вызвать jQuery.ajax в представлении и передать this.successMethod или this.errorMethod в качестве обратных вызовов успеха/ошибки? Будет ли это работать?

Мне нужно синхронизировать с основным мышлением - я знаю, что я определенно отсутствует что-то w.r.t., синхронизация целых коллекций.

Ответ 1

Мое непосредственное размышление заключается не в том, чтобы переопределить метод сохранения метода на Backbone.Collection, а в том, чтобы обернуть коллекцию в другой Backbone.Model и переопределить метод toJSON. Тогда Backbone.js будет рассматривать модель как единый ресурс, и вам не придется взламывать обратный путь слишком много.

Обратите внимание, что Backbone.Collection имеет метод toJSON, поэтому большая часть вашей работы выполняется для вас. Вам просто нужно проксировать метод toJSON вашей оболочки Backbone.Model на 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
 }

});

Ответ 2

Очень просто...

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

... даст вашим коллекциям метод сохранения. Помните, что это всегда будет отправлять все модели коллекции на сервер независимо от того, что изменилось. опции - это просто обычные параметры jQuery ajax.

Ответ 3

Я закончил тем, что просто использовал метод save и назвал $.ajax внутри него. Это дало мне больше контроля над этим без необходимости добавлять класс-оболочку, как предлагал @brandgonesurfing (хотя мне очень нравится идея:) Как уже упоминалось, поскольку у меня уже был метод collection.toJSON(), который был переопределен, все, что я приземлился, использовал его в вызове ajax...

Надеюсь, это поможет кому-то, кто наткнулся на него...

Ответ 4

Это действительно зависит от того, какой контракт между клиентом и сервером. Здесь приведен упрощенный пример CoffeeScript, где PUT to /parent/:parent_id/children с {"children":[{child1},{child2}]} заменит родительских детей тем, что в 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 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').

Ответ 5

Ответ зависит от того, что вы хотите сделать с коллекцией на стороне сервера.

Если вам нужно отправить дополнительные данные с сообщением, вам может понадобиться модель обертки или реляционная модель.

При использовании модели обертки вам всегда нужно написать собственный метод parse:

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

Реляционные модели лучше, я думаю, потому что вы можете легко настроить их и вы можете регулировать с помощью параметра 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);
    }
});

Ответ 6

Я также был удивлен, что коллекции Backbone не имеют встроенного хранилища. Вот то, что я надел на свою базовую коллекцию, чтобы сделать это. Я определенно не хочу перебирать каждую модель в коллекции и сохранять самостоятельно. Кроме того, я использую Backbone на бэкэнд с помощью Node, поэтому я переопределяю собственный Backbone.sync для сохранения в плоский файл на моем маленьком проекте, но код должен быть примерно таким же:

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

Ответ 7

Старый поток, я знаю, что я закончил делать следующее:

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

Довольно преследующая предел:)

Ответ 8

Я бы попробовал что-то вроде:

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

(fooobar.com/questions/69789/...)

Ответ 9

Вот простой пример:

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

Когда вы вызываете метод save() в своей коллекции, он отправляет запрос метода PUT на указанный URL.

Ответ 10

Принятый ответ довольно хорош, но я могу сделать еще один шаг и дать вам код, который обеспечит, чтобы надлежащие события были запущены для ваших слушателей, а также позволяя вам пройти в ответные обратные вызовы 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.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);
}

Ответ 11

Для тех, кто все еще использует backbone.js в 2017 году, принятый ответ не работает.

Попробуйте удалить переопределение toJSON() в модели обертки и вызвать jSON в коллекции при создании экземпляра модели.

new ModelWrapper(Collection.toJSON());