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

2019-03-11 02:13发布

I have a backbone-Model. With model.set() I can set a local value, with model.save() I can save the whole model to the server.

How do I know, whether there was a change since the last server-save meaning the local version is dirty.

model.isNew(); works only if the model has never been saved to the server.

5条回答
我命由我不由天
2楼-- · 2019-03-11 02:19

All answers suggesting listening for changes (using events) are correct unless you pass { silent: true } option. In that case you need to overwrite default set method in order to save attributes that has changed, and reset that list after calling save method.

MidnightLightning's answer is not correct. If you call set method twice then changedAttributes will return only the attributes that has change since last set call - it's in Backbone documentation:

changedAttributesmodel.changedAttributes([attributes])

Retrieve a hash of only the model's attributes that have changed since the last set, or false if there are none.

In my case I solved the problem with this code:

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

If I want to get all changed attributes I use silentChages property inside the model. If I want to trigger event for all set/unset attributes when I save I add 'triggerSilents: true' option. I can also manually trigger all changes event by calling triggerSilentChanges method.

查看更多
成全新的幸福
3楼-- · 2019-03-11 02:26

Alternate option is to set all your updates to 'silent' updates, and then collect the changes when you want to sync:

// 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();
}
查看更多
可以哭但决不认输i
4楼-- · 2019-03-11 02:27

EDIT: This answer was written prior to the 1.0 version of Backbone. As of the current Backbone version (1.2.2) hasChanged no longer reflects "since last save" changes. Instead, it reflects changes "since last set".


Listen for change events or check hasChanged.

If the model has changed, you can save on change. You can even wire your save method to fire when the change event happens.

If you don't want to save on change, then set a property for the model being dirty and clear it when you explicitly save.

Something like:

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

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

isDirty: function(){
    return this.dirty
}
查看更多
萌系小妹纸
5楼-- · 2019-03-11 02:27

I'm working with CouchDB and Couch has a _rev attribute that changes after every save success. I solved the problem of "since-last-server-save" by placing the following code in the models initialize function:

     initialize : function() {
        this.on('change',function(){
            if(this.hasChanged('_rev')) {
                this.isSaved = true;
            }else{
                this.isSaved = false;
            }
        },this);
      }
查看更多
放荡不羁爱自由
6楼-- · 2019-03-11 02:41

Just for reference, I made a little Code Snippet which replaces the default Backbone.sync method.

The replaced Backbone.sync figures out which Attributes has changed since the last save() and it works with both - models and collections.

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

查看更多
登录 后发表回答