我可能不会很好地解释这个......
我正在使用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>
答案 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”,因为它不包含其他信息 - 所有信息都在其他变量中,并且可以计算此值。