可以将breeze生成的observable重新定义为计算字段吗?

时间:2013-11-12 09:38:26

标签: knockout.js breeze

我可能不会很好地解释这个......

我正在使用breeze js来实现一个实体,该实体包含近100个浮点字段。这些是计算结果字段,其中有4个单独的部分,然后是总数,并且重复19次。所以19 x 5 = 95个字段,因此“接近100”。

基本上是:

calculationResult1_materials 
calculationResult1_processes 
calculationResult1_packaging 
calculationResult1_transport 
calculationResult1_total 

calculationResult2_materials 
calculationResult2_processes 
calculationResult2_packaging 
calculationResult2_transport 
calculationResult2_total 

calculationResult3_materials 
etc...

看起来很明显,“total”字段包含其他4个部分的总和但也存储,因为有一个遗留系统只访问该字段,这可以防止每次有人想要的时候都要完成看总数。

由于breeze像其他字段一样将整个字段实现为普通的可观察字段,这意味着每次我重新计算任何计算的其他4个字段中的任何一个字段时,我必须手动重新计算4个单独的组成部分部件(材料,包装,流程,传输)并将结果放入“total”observable中,该observable绑定到显示它的html页面中的div。

虽然这有效,但令我印象深刻的是,这可能不是最有效的做事方式。显然,我可以在我的viewmodel中独立创建19个computedObservable,其中包含每个计算的4个其他字段,然后绑定到它而不是每个实际的“total”observable,但这意味着如果字段名称更改,则手动更新代码。 / p>

有没有办法以某种方式将observable重新定义为computedobservable,这样当计算的其他4个部分中的任何一个发生变化时它会自动计算,并且仍然是实体的一部分,以便之后breeze保存更改?< / p>

2 个答案:

答案 0 :(得分:2)

我不会使用KO计算!

相反,在自定义初始化程序中,我会订阅Breeze EntityAspect.propertyChanged事件,并在EntityType的原型中添加了重新计算功能。)

一旦你根据改变的属性的名称找出更新总计的模式,这将是更轻的权重(一种方法而不是1000s),更高性能,更容易维护。

代码看起来像这样:

function calculationResultCtor() {/*... stuff in the ctor */ }

calculationResultCtor.recalcTotals(propertyName, newValue)
    /* do whatever based on the newValue and the propertyName 
       remember to use the parens required by KO observables
    */
}

function calculationResultInitializer(cr) {
   // listen for any property change in this calculationResult instance
   cr.entityAspect.propertyChanged.subscribe(function(args){
        var propName = args.propertyName;
        if (/_total/.test(propName)) return; // skip changes to total properties
        args.entity.recalcTotals(propName, args.newValue);
   });
}

metadataStore.registerEntityTypeCtor('CalculationResult', 
    calculationResultCtor, calculationResultInitializer);

我可以想到更聪明的方法(例如,计算fns词典,由propertyName键入),以提高效率,但你会看到我要去的地方。

有一件事我会担心(如果这是一个问题,这将是您的KO计算方法过于问题)就是我所说的“的PropertyChanged”风暴,其中一些自动化的过程立即更新很多的属性

该解决方案 - 如果这是一个问题,我不说,这是 - 将使其在风暴期间结束后,当它在锁存重计算时,你只重计算在每一个总单次通过实体。

重点是我开始的地方:不要创建1000个KO计算器!是的,会有1000个,因为你的计划每个实体至少会增加19个计算器,所以只有53个实体实例会让你超过1000个。这样做并不好。

答案 1 :(得分:1)

您应该在应用中使用类似“model.js”的内容来定义Breeze如何处理数据。你应该公开函数configureMetadataStore,你应该放置函数:

function configureMetadataStore(metadataStore){
  metadataStore.registerEntityTypeCtor('MyContainerClassFromServerModel', null, thisClassInitializer);

之后,你需要定义thisClassInitializer,告诉Breeze你要怎么做,就像你所说的那样,“物化对象”:

function thisClassInitializer(myObject){
  myObject.customTotal = ko.computed({
    read: function(){
      return myObject.materials() + myObject.processes() + myObject.packaging() + myObject.transport();
    },
    write: function(newValue){
      myObject.total(newValue);
    }
  });
}

这应该可以解决问题。或者我想到的是,您可以将其定义为:

function thisClassInitializer(myObject){
  myObject.customTotal = ko.computed({
    var newValue = myObject.materials() + myObject.processes() + myObject.packaging() + myObject.transport();
    myObject.total(newValue);
    return newValue;
  });
}

不同之处在于,对于第一个我不能保证不尝试它(不熟练使用这个ko绑定),但对于另一个我很确定它应该有效。

说明: 当你定义这样的东西时,每当Breeze从服务器“实现”一个对象到一个可观察对象时,它也会调用初始化器。通过这种方式,您可以修改对象所具有的字段 - 通常将计算值放在那里(如总计),这样您就不需要将其保存在服务器上。理想情况下,您不需要在服务器上使用“total”,因为它不包含其他信息 - 所有信息都在其他变量中,并且可以计算此值。