backbone.js:自上次服务器保存以来有变化吗

backbone.js: Is there a change since last server-save?

本文关键字:保存 有变化 服务器 js backbone      更新时间:2023-09-26

我有一个主干模型。使用model.set(),我可以设置一个本地值,使用model.save()我可以将整个模型保存到服务器。

我怎么知道,自上次服务器保存以来是否发生了更改,这意味着本地版本已损坏。

model.isNew();仅当模型从未保存到服务器时才有效。


编辑:此答案是在Backbone 1.0版本之前编写的。从当前主干版本(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
}

我正在使用CouchDB,Couch有一个_rev属性,每次保存成功后都会更改。我通过在模型初始化函数中放置以下代码解决了"自上次服务器保存以来"的问题:

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

备用选项是将所有更新设置为"静默"更新,然后在需要同步时收集更改:

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

除非您通过{silent:true}选项,否则所有建议侦听更改(使用事件)的答案都是正确的。在这种情况下,您需要覆盖默认的set方法来保存已更改的属性,并在调用save方法后重置该列表。

午夜闪电的答案不正确。如果您调用set方法两次,那么changedAttributes将只返回自上次set调用以来发生更改的属性-它在主干文档中:

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属性。如果我想在保存时为所有已设置/未设置的属性触发事件,我会添加"triggerSilents:true"选项。我还可以通过调用triggerSilentChanges方法手动触发所有更改事件。

为了参考,我制作了一个小代码段,它取代了默认的Backbone.sync方法。

被替换的Backbone.sync计算出自上次save()以来哪些Attributes发生了更改,并且它同时适用于模型和集合。

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