Resolving model in Backbone.js - Call set with {silent:true} and trigger attribute change events?

喜你入骨 提交于 2019-12-23 04:34:24

问题


I have a chart model like this:

//PSEUDO
chartModel = Backbone.Model.extend({
     defaults: {
         year : 1970,
         selected = ["Sweden", "Denmark"]
     }
 }

I'd now like to set both year & selected:

chartModel.set({year: 1987, selected : ["Finland"]})

But before I trigger the model change I'd like to "resolve" the changes to this unstable model. So I pass silent:true and override the set method:

chartModel.set({year: 1987, selected : ["Finland"]}, {silent:true})

//Pseudo set override
set : function(attrs, options) {

  // Extract attributes and options.
  options || (options = {});
  if (!attrs) return this;
  if (attrs.attributes) attrs = attrs.attributes;
  var now = this.attributes, escaped = this._escapedAttributes;

  [...]

  datamanager.loadNewDataIfNeeded(oldModel, newModel, callback)

I'd specifically like a data manager to "diff" the old attributes vs the new before I trigger the change event:

 callback : function(){
      chartModel.change();
 }

Now - when I know that the right data is in place - I'd like the views to render.

... But my Sidebar view that is bound to change:selected does not render?

Sidebar = Backbone.View.extend({    
    initialize: function(){
        this.model.bind("change:selected", this.render);
    }
    render : [...]
});

My questions:

  1. When triggering model.change() manually, why aren't the individual attribute change events fired?

  2. Do I really need to override the model set method to achieve what I want to ("resolving the model when several attributes are changed at once") or is there a better method?


回答1:


My opinion based upon my understanding of what you are trying to do is this:

  • Rarely or never override the set method; not sure why you feel you have to do it in this case.

  • If you call the set method without {silent: true}, you should get events for change:year and change:selected and change. But objects have to be bound to them to get them. See the bind function.

  • If you call the change function, only the change event is triggered. The attribute level events are not triggered.

It sounds like you should not be overriding the set method and just assure that you have proper binding in those objects that have an interest in this model's changes. Also, eliminate the silent: true passage.

Here's some code based upon your comment:

Thing = Backbone.Model.extend({

  initialize: function(attributes, options) {
    this.bind('change:a', this.calculateC);
    this.bind('change:b', this.calculateC);
  },

  canCalculateC: function() {
    return this.get('a') == someMagicalValueForA && 
           this.get('b') == someMagicalValueForB;
  },

  calculateC: function() {
    if (!this.canCalculateC()) return;
    var self = this;
    $.post('some/url', function(data) {
      var c = // extract value for c
      this.set({c: c});  // which triggers the 'change:c' and 'change' events
    });


  }

});

ThingView = Backbone.View.extend({

  initialize: function(options) {
    this.model.bind("change:c", this.render);
  }

  ...

});

where the model itself is binding to change events for the a and b attributes and handling those by checking to see if it can calculate c, then doing so, then setting the value of c based upon the Ajax return. The model will then trigger 'change:c' for a view to observe. I sketched in the view plumbing which would enable this.

This is untested code, but hopefully conceptually close.



来源:https://stackoverflow.com/questions/6178369/resolving-model-in-backbone-js-call-set-with-silenttrue-and-trigger-attribu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!