Knockout Computed Observable未更新用户界面

时间:2017-01-19 19:54:25

标签: javascript asp.net knockout.js

我遇到了一个问题,尝试将knockoutJS observable更新为计算的observable 动态不会更新UI。

我在复选框上实现了父子依赖关系以下规则控制着交互。

  1. 选中“父复选框”后,将检查所有子复选框。
  2. 取消选中“父复选框”后,将取消选中所有子复选框。
  3. 如果取消选中任何一个子复选框,则应取消选中父复选框。
  4. 选中所有子复选框后,应选中父复选框。
  5. 现在我有一个场景,其中父子依赖行为是动态的,即上述规则仅在用户单击按钮时才开始工作。

    我有一个实现,其中parent复选框绑定到一个可观察的属性,然后该属性被重写为一个新的Computed Observable。 更改为Computed Observable后,前2个规则(规则1和2)工作,但最后2个规则(规则3和4)停止工作。我可以在调试器中看到正确返回了返回值,但它没有更新UI。

    为了证明我的问题,我创建了2个JS小提琴

    1. https://jsfiddle.net/agalo/rjc1Lsbe/4/处的小提琴描述了父子关系规则正常工作的场景。在这种情况下,Computed Observable属性最初在对象上定义,不会动态更改。这非常有效。
    2. https://jsfiddle.net/agalo/uc7yt9tw/4/处的小提琴描述了我目前的规则3和规则4不起作用的实施方式。在这种情况下,单击按钮时,将使用计算的Observable覆盖Observable属性。因此,最初不强制执行父子关系,但是单击按钮可以强制执行关系。
    3. 我不是在寻找替代解决方案,但我有兴趣了解为什么第二个小提琴显示行为。

      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>

1 个答案:

答案 0 :(得分: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.childrencomputed之前已经有值时,这个函数如何能够使它工作? $str = "_{test_1} != '' || _{_str_test_2} != 'Yes' && _{_test_str_3} == 'Yes'"; $pattern = '#{(.*?)}#s'; preg_match_all($pattern,$str,$matches); print_r($matches); 已创建: - )

更新了fiddle