Backbone.js: Есть ли изменения с момента последнего сохранения сервера? - программирование
Подтвердить что ты не робот

Backbone.js: Есть ли изменения с момента последнего сохранения сервера?

У меня есть модель-позвоночник. С model.set() я могу установить локальное значение с помощью model.save() Я могу сохранить всю модель на сервере.

Как узнать, произошло ли изменение с момента последнего сохранения сервера, что означает, что локальная версия неактивна.

model.isNew(); работает только в том случае, если модель никогда не была сохранена на сервере.

4b9b3361

Ответ 1


EDIT: Этот ответ был написан до версии Backbone версии 1.0. Начиная с текущей версии Backbone (1.2.2) hasChanged больше не отражается "с момента последнего сохранения". Вместо этого он отражает изменения "с последнего набора".


Слушайте события изменения или отметьте hasChanged.

Если модель изменилась, вы можете сохранить ее при изменении. Вы можете даже подключить свой метод сохранения, чтобы он срабатывал, когда происходит событие изменения.

Если вы не хотите сохранять изменения, установите свойство для грязной модели и очистите ее, когда вы явно сохраните.

Что-то вроде:

change: function(){
    this.dirty = true;
}

save: function(){
    // do your save
    if(success){
        this.dirty = false;
    }
}

isDirty: function(){
    return this.dirty
}

Ответ 2

Я работаю с CouchDB, а Couch имеет атрибут _rev, который изменяется после каждого успеха сохранения. Я решил проблему "after-last-server-save", поместив следующий код в функцию инициализации моделей:

     initialize : function() {
        this.on('change',function(){
            if(this.hasChanged('_rev')) {
                this.isSaved = true;
            }else{
                this.isSaved = false;
            }
        },this);
      }

Ответ 3

Альтернативный вариант - установить все ваши обновления в "тихие" обновления, а затем собрать изменения, когда вы хотите синхронизировать:

// Updates
myModel.set({foo: 'bar'}, {silent: true}); // Does not fire a 'changed' event
myModel.set({foobar: 'barfoo'}, {silent: true});

// Sync
if (myModel.hasChanged()) {
  console.log(myModel.changedAttributes()); // {'foo':'bar', 'foobar':'barfoo'}
  _.each(myModel.changedAttributes(), function(value, key) {
    console.log(key+' used to be '+myModel.previous(key)+', but now is '+value);
  }
  myModel.save();
}

Ответ 4

Все ответы, предлагающие прослушивание изменений (используя события), верны, если вы не передадите параметр {silent: true}. В этом случае вам необходимо перезаписать метод установки по умолчанию, чтобы сохранить измененные атрибуты, и reset, который после вызова метода сохранения.

Ответ MidnightLightning неверен. Если вы вызовете метод set дважды, то changedAttributes вернет только атрибуты, которые имеют изменения с момента последнего установленного вызова - это в документации Backbone:

changedAttributesmodel.changedAttributes([attributes])

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

В моем случае я решил проблему с этим кодом:

(function(_, Backbone) {
  'use strict';

  var _set = Backbone.Model.prototype.set,
    _save = Backbone.Model.prototype.save;

  _.extend(Backbone.Model.prototype, {
    set: function(key, val, options) {
      var options = this._getOptions(key, val, options), 
        toReturn = _set.call(this, key, val, options);
      if(!_.isUndefined(options) && options.silent && !!this.changedAttributes()) {
        this.silentChanges = _.extend([], this.silentChanges);
        [].push.apply(this.silentChanges, _.keys(this.changedAttributes()));
      }
      return toReturn;
    },
    save: function(key, val, options) {
      var options = this._getOptions(key, val, options),
        toReturn = _save.call(this, key, val, options);
      if(!_.isUndefined(options) && options.triggerSilents) {
        this.triggerSilentChanges();
      }
      return toReturn;
    },
    unset: function(key, options) {
      if(!_.isUndefined(options) && options.silent) {
        this.silentChanges = _.extend([], this.silentChanges, _.keys(this.changedAttributes()));
      }
    },
    triggerSilentChanges: function() {
      if(!_.isEmpty(this.silentChanges)) {
        var that = this;
        _.each(this.silentChanges, function(key) {
          that.trigger('change:' + key);
          that.silentChanges = _.without(that.silentChanges, key);
        });
        Backbone.Model.prototype.trigger.call(this, 'change');
      }
    },
    _getOptions: function(key, val, options) {
      if(key == null || _.isObject(key)) {
        return val;
      }
      return options;
    }
  });
})(_, Backbone);

Если я хочу получить все измененные атрибуты, я использую свойство silentChages внутри модели. Если я хочу инициировать событие для всех атрибутов set/unset при сохранении, я добавляю параметр "triggerSilents: true". Я также могу вручную запустить все события изменений, вызвав метод triggerSilentChanges.

Ответ 5

Для справки я сделал небольшой фрагмент кода, который заменяет метод Backbone.sync по умолчанию.

Замененный Backbone.sync определяет, какие атрибуты изменились со времени последнего сохранения(), и он работает с обоими моделями и коллекциями.

https://github.com/ChiefORZ/backbone.dirty-sync