Knockout Computed Observed does not update user interface

I ran into a problem when trying to update a JS knockout observed to a computed observed dynamically does not update the user interface.

I applied the parent-child dependency to the checkboxes. The following rules govern the interaction.

  • When the Parent flag is checked, then all the flags of the child are checked.
  • If the "Parent flag" is not checked, then all the flags of the child are unchecked.
  • If none of the child checkboxes is checked, the parent checkbox must be unchecked.
  • When the checkbox for the child is checked, check the checkbox of the parent checkbox.

Now I have a scenario in which the behavior of dependencies between parents and children is dynamic, that is, Above rules only start when the user clicks a button.

I have an implementation in which the parent flag is attached to a property that can be observed, and then the property is redefined to a new computed observation. After switching to Computed Observable, the first 2 rules (rules 1 and 2) work, but the last 2 rules (rules 3 and 4) stop working. In the debugger, I see that the return value is returned, but it does not update the user interface.

To demonstrate my problem, I created 2 JS scripts

, , .

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>
Hide result
+4
1

, , . -

  • parentCheckBox observable self.parentChildData.
  • self.parentChildData.children -.
  • parentCheckBox computed observable.

, , , , parentCheckBox , self.parentChildData.children, , , , .

, self.parentChildData.children , parentCheckBox computedObservable ( , ).

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

, self.makeDependent, , , self.parentChildData.children , computed : -)

fiddle.

+1

Source: https://habr.com/ru/post/1667290/


All Articles