2017-08-04 88 views
1

把这个代码:淘汰赛认购不叫改变观察的数组时

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. 为什么订阅(alert("Subscribe called!");)在最初的isValid为true并且以后设置为false时未被调用?我期望在我的代码中调用两次。

感谢

回答

2

有与该代码的几个问题,但相对于你问的主要问题是,在可观察到的排列变换对象上的不可观测性(valid)是不改变可观察数组,只是它内部对象的一个​​属性。所以自然没有通知。如果你想要通知,你需要看valid属性(这意味着它必须是可观察的)。

其他问题:

  1. 一个与淘汰赛的问题是,它有时解开观测/ computeds你,但如果他们的表达它的一部分   —你必须这样做(与()):

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

    你的代码是在试探是否isValid(不是isValid())是truthy。它始终是,因为它是一个函数参考。

    仅当标识符不是表达式的一部分时,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,但随后也通过thiscomputed使用bindsubscribe 。这是无害的,但毫无意义。一个或另一个是你需要的。

  4. 不需要创建一个新的独立对象作为您的虚拟机构造函数的返回值;你已经有一个对象(由new创建的对象)。

下面是各种变化的例子。该valid财产上的第一项设置为false 800毫秒后:

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>

+0

谢谢! ...以及我被告知要使用Stack Snippets而不是Fiddle ...所以通常我会更新小提琴并在“答案”中提供新的小提琴链接......但是我看不到我如何更新代码没有在这个问题上做? – MojoDK

+0

@MojoDK:你不能。当不可避免的做到这一点时,最好的办法就是在第一句话“我尝试做X回答但它仍然不起作用:”或类似的东西时加上第二个片段。 (然后一旦有必要的答案,你可以再次删除它。)这样做很重要,以限制它已经存在的问题(问题并不意味着移动目标)。在这种情况下,他们是,所以它会没事的。很高兴帮助! –