【问题标题】:Knockout Computed Observable not updating the UIKnockout Computed Observable 不更新 UI
【发布时间】:2017-06-04 16:02:37
【问题描述】:

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

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

  1. 选中父母复选框时,请选中所有子女复选框。
  2. 当父 Checkbox 被取消选中时,所有子 Checkbox 都被取消选中。
  3. 当任何一个子Checkbox被取消选中时,那么父Checkbox应该被取消选中。
  4. 当所有子复选框都被选中时,父复选框应该被选中。

现在我有一个场景,父子依赖行为是动态的,即上述规则仅在用户单击按钮时才开始工作。

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

为了演示我的问题,我创建了 2 个 JS fiddle

  1. https://jsfiddle.net/agalo/rjc1Lsbe/4/ 的 Fiddle 描述了父子关系规则正常工作的场景。在这种情况下,Computed Observable 属性最初是在对象上定义的,并且不会动态更改。这非常有效。
  2. https://jsfiddle.net/agalo/uc7yt9tw/4/ 的 Fiddle 描述了我当前的实现,其中规则 3 和 4 不起作用。在这种情况下,单击按钮时计算的 Observable 会覆盖 Observable 属性。因此,最初不强制执行父子关系,但在单击按钮时会强制执行关系。

我不是在寻找替代解决方案,但我有兴趣了解为什么第二个小提琴会显示该行为。

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>

【问题讨论】:

    标签: javascript asp.net knockout.js


    【解决方案1】:

    我想问题在于初始化设置时发生的一系列事件。考虑在您的实施中遵循流程 -

    • parentCheckBox 首先定义为 self.parentChildData 上的 observable 属性。
    • self.parentChildData.children 数组使用子项初始化。
    • parentCheckBox 现在更改为 computed observable

    我在这里看到的问题是,在要求 parentCheckBoxself.parentChildData.children 中对子项所做的更改做出反应之前,此子项数组已经初始化,因此没有创建依赖项,这就是为什么你没有得到你期望的行为。

    所以,我稍微改变了你的代码流程并在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
    

    此外,这消除了对self.makeDependent 函数的需要,尽管我也很奇怪,当self.parentChildData.childrencomputed 之前已经有值时,这个函数是如何使其工作的创建:-)

    更新fiddle

    【讨论】:

    • 您在此处描述的解决方案与我的第一个正在运行的方案完全匹配,我试图了解 为什么在属性 self.parentChildData.parentCheckBox 更改时规则 3 和 4 不起作用从ObservableComputedObservable 动态,意思是在某个事件上改变。您描述的场景甚至在模型绑定到 UI 之前直接覆盖属性,这不是我的场景 2。
    • 如果我在这里不清楚,请原谅我,但是当您在此处提到 a certain event 时,您是否指向函数 self.makeDependent含义因某个事件而改变
    • 我所说的某些事件的意思是函数self.makeDependent被触发为在html中定义的点击` `。因此,单击只是调用此函数的一种方式。我希望它能解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-15
    • 2018-05-26
    • 1970-01-01
    • 2015-10-25
    • 2016-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多