运行时的EmberJS动态观察程序

EmberJS dynamic observers at run-time?

本文关键字:观察 程序 动态 EmberJS 运行时      更新时间:2023-09-26

给定以下模型:

(注意:为了便于说明,这些都被简化了)

App.CustomerOrder = DS.Model.extend({
  deliveries: DS.hasMany('delivery'),
  total: DS.attr('number')
});
App.Delivery = DS.Model.extend({
  orderlines: DS.hasMany('orderline')
});
App.OrderLine = DS.Model.extend({
  productid: DS.attr('string'),
  qtyordered: DS.attr('number')
});

当应用程序第一次加载时,我正在查询一个API,该API向我发送有关哪些依赖项应该触发更新的信息。例如,它会给我发一些类似的东西:

CustomerOrder: ["deliveries", "deliveries.orderlines", "deliveries.orderlines.qtyordered"...]

是指,如果从客户订单中添加/删除了交货,或者如果从附加到客户订单的交货中添加或删除了行,或者如果在附加到客户命令的交货的订单行上订购了qtyor,那么API希望我序列化CustomerOrder(以及整个关系链),并将其发送到"更新"服务(即服务器/客户订单/更新类型的东西),该服务将运行各种例程和填充数据,并将整个对象链发送回。

为了便于说明,我在这里放了一个简单的ordertotal示例(我意识到这在客户端很容易计算,但还有很多其他内容会与服务器的代码重复)。因此,如果订单行上的qtyorder发生更改,我需要将customerorder实例发送到服务器,它将在那里更新我的total字段。

其中一个挑战是,我不能通过用.observers()类型的东西设置observer函数来硬编码依赖列表,它必须在加载依赖数据后动态完成(可能使用addObserver)。另一个是,观察者不会像那样深入挖掘多层。

我已经尝试过在模型中使用一个mix-in来覆盖init函数,并且确实做到了这一点。

clientchangeset: DS.attr('raw'),
init: function() {
  this._super.apply(this, arguments);
  var className = this.auth.camelizedModelString(this.constructor.toString());
  var watchlist = this.auth.dependencies[className] || null;
  var self = this;
  watchlist.forEach(function(watch) {
    if(watch.hasOwnProperty('attributeName') && watch.hasOwnProperty('collectionFlag')) {
      // {attributeName: attributeName, collectionFlag: collectionFlag}
      if(watch['collectionFlag']) {
        console.log(className+'.addObserver('+watch['attributeName']+'.@each.clientchangeset)');
        self.addObserver(watch['attributeName']+'.@each.clientchangeset', null, 'updateChangelist');
      } else {
        console.log(className+'.addObserver('+watch['attributeName']+')');
        self.addObserver(watch['attributeName'], null, 'updateChangelist');
      }  
    }
  });
},

这似乎有效,但只有一层深。为了完整起见,这里有updateChangelist函数:

updateChangelist: function(src, field, value) { //jshint ignore:line
  if(this.get('pauseUpdates')) {
    return;
  }
  var className = this.auth.camelizedModelString(this.constructor.toString());
  var oldclientchangeset = this.get('clientchangeset') || [];
  console.log('Before: '+className+'.[clientchangeset]= '+oldclientchangeset);
  oldclientchangeset.pushObject(field);
  this.set('clientchangeset', oldclientchangeset);
  console.log('After: '+className+'.[clientchangeset]= '+oldclientchangeset);
}

因此,通常情况下,我实现这一点的方法是按照指示创建观察程序,但处理程序只需在触发关系时在每个级别上更新一个名为"_needsUpdate"的属性_needsUpdate只是一个日期,所以当触发时我会:

this.set('_needsUpdate', +new Date());

然后,当为该级别的孩子在每个级别设置观察者时,我只设置一个观察者来观察孩子@每个_需要更新。