为什么这些Knockout订阅会通知一个根本不应该订阅的对象

时间:2015-07-23 20:36:54

标签: javascript jquery knockout.js

请在此处查看:JSFiddle

这是html:

<script src="http://code.jquery.com/jquery-2.1.4.min.js" ></script>

<div id="first">
<button data-bind="click: toggleColumn">Click me!</button>
</div>
<ul id="list_test">
    <!-- ko foreach: list -->
    <li data-bind="text: $data.ColName"></li>
    <!-- /ko -->
</ul>

这是javascript:

function ViewModel(){
    var self = this;
    self.showColumn = ko.observable(true);
    self.toggleColumn = function(){
        self.showColumn(!self.showColumn());
    };

    self.ListOfObjects = [
        {ColName: 'test1', visible: self.showColumn},
        {ColName: 'test2'},
        {ColName: 'test3', visible: self.showColumn},
        {ColName: 'test4'},
        {ColName: 'test5'},
    ];

};

function TestViewModel(params){
    var self = this;
    self.list = ko.observableArray();
    for(var i = 0; i < params.length; i++){
        var obj = params[i];
        if(!obj.visible){
            //obj.visible = ko.observable(true);
        }

        if(obj.visible){
            obj.visible.subscribe(function(){
                    var elements = $('li');
                    for(var i = 0; i < elements.length; i++){
                        if($(elements[i]).text() == obj.ColName){
                            $(elements[i]).hide();
                        }
                    }
                });
        }

        self.list.push(obj);
   }
}

function initViewModel(){

    var mod = new ViewModel();
    ko.applyBindings(new TestViewModel(mod.ListOfObjects),document.getElementById("list_test"));
    ko.applyBindings(mod,  document.getElementById("first"));


}

initViewModel();

所以我的问题是这个。为什么当你点击按钮时,&#39; test5&#39;列表项被隐藏而不是两个订阅对象(test1和test3)?似乎总是默认隐藏列表的末尾。

我用我的实际代码完成了这个,因为JSFiddle只是错误的准系统复制,我通过Chrome的控制台/调试器检查了所有内容。

在subscribe调用中,与showColumn变量相比,obj.visible属性不是同一个实例。如果你在订阅调用中的obj.visible上获得了SUBscriptionsCount,那么你只能获得一个它应该永远不会获得的订阅,因为它永远不会被定义。如果你在&#39; test1&#39;和&#39; test3&#39;您可以获得2个订阅的可见属性(如预期的那样),它们是与ViewModel.showColumn相同的实例的引用。

仍然在订阅中,如果你检查obj的值,你就会得到

{ColName: 'test5', visible: /*some knockout obj*/}

它永远不应该从&#39; test5&#39;中调用subscribe。它应该来自&#39; test1&#39;和&#39; test3&#39;。

现在,如何通过&#39; item5&#39;来通知obj.visible.subscribe。当&#39; item5&#39;对象从未收到对ViewModel.showColumns的引用?如何为&item 39&#39;?

定义可见性

对我而言,它看起来像是对另一个ko.observable对象的订阅通知订阅完全不同(甚至不存在)ko.observable。我很确定不应该发生......

1 个答案:

答案 0 :(得分:1)

这是一个经典的&#34;关闭&#34;错误。您的obj变量在for循环的生命周期内发生变化,其所持有的最后一个值指向&#34; test5&#34;。事件处理函数使用相同的变量,因此当事件被触发时,它会查找&#34; test5&#34;并隐藏。您可以使用标准闭合和解决方案解决这个问题IIFE。

这是重要的代码:

if(obj.visible){
  (function (obj) {
    obj.visible.subscribe(function(){
      var elements = $('li');
      for(var i = 0; i < elements.length; i++){
        if($(elements[i]).text() == obj.ColName){
          $(elements[i]).hide();
        }
      }
    });
  })(obj);
}

这是一个固定的fiddle