javascript - 更改可观察数组时不调用 knockout 订阅

标签 javascript jquery knockout.js

拿这段代码:

var koEvents = new ko.subscribable();

var viewModel = function() {
   var self = this;

   self.data = ko.observableArray([{
      valid: true
   }, {
      valid: true
   }]);

   self.isValid = ko.computed(function() {
      var isValid = true;
      ko.utils.arrayForEach(self.data(), function(item) {
         console.log(item.valid);
         if (!item.valid) {
            isValid = false;
            return;
         };
      });
      return isValid;
   }, this).subscribe(function(newValue) {
      alert("Subscribe called!");
      koEvents.notifySubscribers(newValue, "dataChanged");
   }.bind(this));

   return {
      data: self.data,
      isValid: self.isValid,
   };
}

var vm = new viewModel();
ko.applyBindings(vm, document.getElementById("container"));

vm.data()[0].valid = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="container">
   <div data-bind="text: isValid ? 'valid': 'invalid'">
   </div>
</div>

我有两个问题...

  1. 当我这样做时,为什么 self.isValid 没有被调用 vm.data()[0].valid = false;
  2. 为什么当 isValid 最初为 true 后来设置为 false 时不调用 subscribe (alert("Subscribe called!");)?我希望它在我的代码中被调用两次。

谢谢

最佳答案

该代码有几个问题,但与您所问的内容相关的主要问题是更改可观察数组中对象的不可观察属性(有效)不是更改可观察数组,只是其中对象的一个​​属性。所以自然没有通知。如果你想要通知,你需要观察 valid 属性(这反过来意味着它必须是可观察的)。

其他问题:

  1. Knockout 的一个问题是它有时会为您解包 observables/computeds,但如果它们是表达式的一部分,它不会 — 你必须这样做(使用 ()):

    <div data-bind="text: isValid() ? 'valid': 'invalid'"></div>
    <!-- ------------------------^^                          -->
    

    您的代码正在测试 isValid(不是 isValid())是否为真。它始终是,因为它是一个函数引用。

    KO 仅在标识符不是表达式的一部分时为您自动展开。例如,这有效:

    <!-- Works -->
    <div data-bind="visible: isValid">...</div>
    

    但这不是:

    <!-- Doesn't work -->
    <div data-bind="visible: !isValid">...</div>
    

    (当 isValid 是可观察/计算时)。

  2. 您正在将 self.isValid 设置为 订阅句柄,而不是计算的句柄,因为您过度链接了。 :-) 你需要在computed调用结束后完成赋值,然后然后订阅:

    self.isValid = ko.computed(function() {
       // ...
    }, this); // <=== End the assignment here
    self.isValid.subscribe(function(newValue) {
       // ...
    }.bind(this));
    
  3. 您正在使用 self = this,但随后还将 this 传递给 computed 并使用 bindsubscribe。这是无害的,但毫无意义。一个或另一个就是您所需要的。

  4. 无需创建新的单独对象作为 VM 构造函数的返回值;您已经有一个对象(由 new 创建的对象)。

这是一个包含这些不同变化的示例。第一个条目的 valid 属性在 800 毫秒后设置为 false:

var koEvents = new ko.subscribable();

var viewModel = function() {
   this.data = ko.observableArray([{
      valid: ko.observable(true)
   }, {
      valid: ko.observable(true)
   }]);

   this.isValid = ko.computed(function() {
      var isValid = true;
      ko.utils.arrayForEach(this.data(), function(item) {
         console.log(item.valid());
         if (!item.valid()) {
            isValid = false;
            return;
         };
      });
      return isValid;
   }, this);
   this.isValid.subscribe(function(newValue) {
      alert("Subscribe called!");
      koEvents.notifySubscribers(newValue, "dataChanged");
   });
}

var vm = new viewModel();
ko.applyBindings(vm, document.getElementById("container"));

setTimeout(function() {
  vm.data()[0].valid(false);
}, 800);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="container">
   <div data-bind="text: isValid() ? 'valid' : 'invalid'"></div>
</div>

关于javascript - 更改可观察数组时不调用 knockout 订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45502475/

相关文章:

javascript - html 元素的 "dir"属性 (rtl/ltr) 的数据绑定(bind)

javascript - 更改 JavaScript 对象中的键名

javascript - 如何使用构建脚本在没有 npm 的情况下将 JSX 转换为 JS?

javascript - 如何使 document.location.href 表现得像一个简单的链接?

javascript - 另一个 JavaScript 数组挑战

javascript - TypeError : ko. 可观察数组不是函数

javascript - 创建此号码的最快方法?

javascript - 如何在 vue.js 2 上添加类?

javascript - ajax后Laravel刷新数据

javascript - 设置为本地存储 knockout 后更新 View