解析 Backbone.js 中的模型 - 使用 {silent:true} 调用集并触发属性更改事件?

发布于 2024-11-10 05:30:38 字数 1330 浏览 0 评论 0原文

我有一个这样的图表模型:

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

我现在想设置年份和年份。 selected:

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

但在触发模型更改之前,我想“解决”对此不稳定模型的更改。因此,我传递silent:true并覆盖set方法:

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)

我特别希望数据管理器在触发更改事件之前“区分”旧属性与新属性:

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

现在 - 当我知道正确的数据已就位时 -我想要渲染视图。

...但是我的侧边栏视图必然会发生变化:selected 不会呈现?

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

我的问题:

  1. 手动触发 model.change() 时,为什么没有触发各个属性更改事件?

  2. 我真的需要重写模型设置方法来实现我想要的(“当多个属性同时更改时解析模型”)还是有更好的方法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

年华零落成诗 2024-11-17 05:30:38

根据我对您想要做的事情的理解,我的观点是:

  • 很少或从不重写 set 方法;不知道为什么你觉得在这种情况下必须这样做。

  • 如果您在没有 {silent: true} 的情况下调用 set 方法,您应该获得change:year 和change:selected 和change 的事件。但必须将对象绑定到它们才能获取它们。请参阅bind 函数。

  • 如果调用change函数,则只会触发change事件。不会触发属性级别事件。

听起来您不应该重写 set 方法,而只需确保您在对此模型的更改感兴趣的那些对象中具有正确的绑定即可。另外,消除沉默:真实的段落。

这是根据您的评论编写的一些代码:

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

  ...

});

其中模型本身绑定 a 和 b 属性的更改事件,并通过检查是否可以计算 c 来处理这些事件,然后执行此操作,然后根据 Ajax 返回设置 c 的值。然后模型将触发“change:c”以观察视图。我在视图管道中绘制了草图,这将实现这一点。

这是未经测试的代码,但希望在概念上接近。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文