简体   繁体   English

Knockout Computed Observable不更新UI

[英]Knockout Computed Observable not updating the UI

I am running into a problem, where trying to update a knockoutJS observable to a computed observable dynamically doesn't update the UI. 我遇到了一个问题,尝试将knockoutJS observable 动态更新为计算的observable不会更新UI。

I have implemented a parent-child dependent Relationship on the Checkboxes Following rules govern the interaction. 我已经在复选框上实现了父子依赖关系以下规则控制着交互。

  1. When Parent Checkbox is checked, Then all the child Checkbox are checked. 选中“父复选框”后,将选中所有子复选框。
  2. When Parent Checkbox is unchecked, Then all the child Checkbox are unchecked. 取消选中“父复选框”后,将取消选中所有子复选框。
  3. When any one of the child Checkbox is unchecked, Then parent Checkbox should be unchecked. 如果未选中任何一个子复选框,则应取消选中父复选框。
  4. When all of the child checkbox are checked, Then parent Checkbox should be checked. 选中所有子复选框后,应选中父复选框。

Now i have a scenario, where the parent-child dependency behavior is dynamic, ie the Above rules start working only when the user clicks the button. 现在我有一个场景,其中父子依赖行为是动态的,即上述规则仅在用户单击按钮时才开始工作。

I have an implementation where the parent checkbox binds to a property which is observable and later the property is overridden to a new Computed Observable. 我有一个实现,其中父复选框绑定到一个可观察的属性,然后该属性被重写为新的Computed Observable。 After changing to the Computed Observable, the first 2 Rules (Rule 1 & 2) works but last 2 Rule (Rule 3 & 4) stops working. 更改为Computed Observable后,前2个规则(规则1和2)有效,但最后2个规则(规则3和4)停止工作。 I can see in the debugger that the return value is correctly returned but it doesn't Update the UI. 我可以在调试器中看到正确返回了返回值,但它没有更新UI。

To demonstrate my problem, i have created 2 JS fiddle 为了证明我的问题,我创造了2个JS小提琴

  1. Fiddle at https://jsfiddle.net/agalo/rjc1Lsbe/4/ describes the scenario where the parent child relationship rules are working fine. https://jsfiddle.net/agalo/rjc1Lsbe/4/上的小提琴描述了父子关系规则正常工作的场景。 In this case, the Computed Observable property is defined initially on the object and is not changed dynamically. 在这种情况下,Computed Observable属性最初在对象上定义,不会动态更改。 This works perfectly. 这非常有效。
  2. Fiddle at https://jsfiddle.net/agalo/uc7yt9tw/4/ describes my current implementation for which Rule 3 and 4 are not working. https://jsfiddle.net/agalo/uc7yt9tw/4/中的小提琴描述了我当前的规则3和4不起作用的实现。 In this case, the Observable property is overridden with the computed Observable on the click of the button. 在这种情况下,单击按钮时,将使用计算的Observable覆盖Observable属性。 So, initially the parent child relationship is not enforced, but on click of button the relationship is enforced. 因此,最初不会强制执行父子关系,但是在单击按钮时会强制执行关系。

I am not looking for alternative solutions but i am interested to understand as to why the second fiddle shows the behavior. 我不是在寻找替代解决方案,但我有兴趣了解为什么第二小提琴显示行为。

 function ViewModel(){ var self = this; var childrenArray = [ {isSelected : ko.observable(true)}, {isSelected : ko.observable(true)}, {isSelected : ko.observable(true)}, {isSelected : ko.observable(true)}]; self.parentChildData = { parentCheckBox: ko.observable(false), children: ko.observableArray([]) }; self.parentChildData.children(childrenArray); self.makeDependent = function(){ self.parentChildData.parentCheckBox = ko.computed({ read: function () { var anyChildUnChecked = ko.utils.arrayFirst(self.parentChildData.children(), function (childCheckBox) { return !childCheckBox.isSelected(); }); var result = anyChildUnChecked == null; return result; //return false; }, write: function (value) { ko.utils.arrayForEach(self.parentChildData.children(), function (childCheckBox) { childCheckBox.isSelected(value); }); } })}; return self; } ko.applyBindings(new ViewModel()); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script> <p> Describes my current implementation for which Rule 3 and 4 are not working. In this case, the Observable property is overridden with the computed Observable on the click of the button. So, initially the parent child relationship is not enforced, but on click of button the relationship is enforced. </p> <p> After clicking the button, the first 2 Rules (Rule 1 and 2) works but last 2 Rule (Rule 3 and 4) stops working. I can see in the debugger that the return value is correctly returned but it doesn't Update the UI. </p> <div id="parent"> parent <input type="checkbox" data-bind="checked:parentChildData.parentCheckBox"/> <br/> <div id="child"> Child <!-- ko foreach: parentChildData.children --> <input type="checkbox" data-bind="checked:isSelected"/> <!-- /ko --> </div> <br/> <input type="button" value="Make dependent" data-bind="click:makeDependent"> </div> 

I guess the issue is with the sequence of events that are happening at the time of initialization of your setup. 我想问题是在初始化设置时发生的事件序列。 Consider following flow in your implementation - 考虑实施中的以下流程 -

  • parentCheckBox is first defined as an observable property on self.parentChildData . parentCheckBox首先被定义为self.parentChildData上的一个observable属性。
  • self.parentChildData.children array is initialized with children items. self.parentChildData.children数组使用子项初始化。
  • parentCheckBox is now changed to a computed observable . parentCheckBox现在更改为computed observable

The issue I see here is that before the parentCheckBox was asked to react to the changes made to the children in self.parentChildData.children , this children array was already initialized and hence that dependency was not created which is why you were not getting the behavior you expect. 我在这里看到的问题是,在parentCheckBox被要求对self.parentChildData.childrenself.parentChildData.children所做的更改作出反应self.parentChildData.children ,这个children数组已经初始化,因此没有创建依赖关系,这就是为什么你没有得到这种行为你期待。

So, I changed the flow of your code a bit and initialized the self.parentChildData.children after the parentCheckBox was assigned a role of computedObservable (though it does not change how it was initially defined). 因此,我更改了代码的流程并在parentCheckBox被赋予了computedObservable角色之后初始化了self.parentChildData.children (虽然它不会改变最初定义的方式)。

self.parentChildData.parentCheckBox = ko.computed({

read: function() {
  var anyChildUnChecked = ko.utils.arrayFirst(self.parentChildData.children(), function(childCheckBox) {
    return !childCheckBox.isSelected();
  });
  var result = anyChildUnChecked == null;
  return result;

  //return false;
},

write: function(value) {
  ko.utils.arrayForEach(self.parentChildData.children(), function(childCheckBox) {
    childCheckBox.isSelected(value);
  });
}
});

self.parentChildData.children(childrenArray); //values are pushed here

Also, this removes the need for the self.makeDependent function, though it is strange to me as well that how was this function able to make it work when still the self.parentChildData.children was already having values before the computed was created :-) 此外,这消除了对self.makeDependent函数的需要,虽然我也很奇怪,当self.parentChildData.children在创建computed之前已经具有值时,该函数如何能够使其工作: - )

Updated fiddle . 更新了小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM