2014-11-14 66 views
1

我一直在尝试做复选框Checkall和UnCheckall使用订阅和我部分成功做到这一点,但我无法找到一个解决方案时,我正在处理subscribeCheckAll/UncheckAll订阅的问题?敲除

使用订阅:

我在这里能够checkAll uncheckAll但是当我取消一个孩子复选框即test1test2我需要我的父母复选框name也被选中,并在下一回合,如果我检查test1的家长复选框应该被检查,即保持条件两个孩子复选框被检查。

对于小提琴:Click Here

视图模型:

self.selectedAllBox.subscribe(function (newValue) { 
     if (newValue == true) { 
      ko.utils.arrayForEach(self.People(), function (item) { 
       item.sel(true); 
      }); 
     } else { 
      ko.utils.arrayForEach(self.People(), function (item) { 
       item.sel(false); 

      }); 
     } 
    }); 

相同的情况下,可以使用computed简单的方法完全可以做到的,但由于一些性能问题,我需要使用subscribe这是最好的方式,不会像计算的onload那样开火。

参考:使用计算机一样的东西是完全可以做到的检查这个Fiddle

我试图用个人复选框change事件绑定,但它是一个死胡同至今。

任何帮助表示赞赏。

回答

1

我在自己的应用程序解决了类似的问题几年前,使用手动订阅。虽然计算的可观测方法简洁易懂,但在有大量项目时性能较差。希望下面的代码不言自明:

function unsetCount(array, propName) { 
    // When an item is added to the array, set up a manual subscription 
    function addItem(item) { 
     var previousValue = !!item[propName](); 
     item[propName]._unsetSubscription = item[propName].subscribe(function (latestValue) { 
      latestValue = !!latestValue; 
      if (latestValue !== previousValue) { 
       previousValue = latestValue; 
       unsetCount(unsetCount() + (latestValue ? -1 : 1)); 
      } 
     }); 
     return previousValue; 
    } 
    // When an item is removed from the array, dispose the subscription 
    function removeItem(item) { 
     item[propName]._unsetSubscription.dispose(); 
     return !!item[propName](); 
    } 

    // Initialize 
    var tempUnsetCount = 0; 
    ko.utils.arrayForEach(array(), function (item) { 
     if (!addItem(item)) { 
      tempUnsetCount++; 
     } 
    }); 
    var unsetCount = ko.observable(tempUnsetCount); 

    // Subscribe to array changes 
    array.subscribe(function (changes) { 
     var tempUnsetCount = unsetCount(); 
     ko.utils.arrayForEach(changes, function (change) { 
      if (change.moved === undefined) { 
       if (change.status === 'added') { 
        if (!addItem(change.value)) 
         tempUnsetCount++; 
       } else { 
        if (!removeItem(change.value)) 
         tempUnsetCount--; 
       } 
      } 
     }); 
     unsetCount(tempUnsetCount); 
    }, null, 'arrayChange'); 

    return unsetCount; 
} 

你仍然将使用一个计算观察到在你的视图模型的选择,所有的价值,但现在就只需要检查未选择的计数

self.unselectedPeopleCount = unsetCount(self.People, 'Selected'); 

self.SelectAll = ko.pureComputed({ 
    read: function() { 
     return self.People().length && self.unselectedPeopleCount() === 0; 
    }, 
    write: function(value) { 
     ko.utils.arrayForEach(self.People(), function (person) { 
      person.Selected(value); 
     }); 
    } 
}).extend({rateLimit:0}); 

例子:http://jsfiddle.net/mbest/dwnv81j0/

2

您的订阅仅适用于selectedAllBox上的编辑。要做你想做的事,你也需要在每个人的复选框上进行订阅,以检查正确的条件,并在那里的正确情况下取消选中selectedAllBox。

它让我觉得奇怪,这是可以接受的,但使用computed()不是。也许你应该重新考虑你的答案。我宁愿计算基于我的viewModel状态的“isAllSelected”值,然后将selectedAllBox绑定到该值。

+0

他是对的。计算是这样做的最好方法。 – 2014-11-14 18:50:41

+0

@帕特里克那伟大的洞察力。是的,我已经尝试订阅儿童复选框,即事件:{更改:$ root.checkevaluate}'。在'checkevaluate'我试图以适当的方式做我的评估,但我卡住了。 – 2014-11-14 19:48:10

+0

@MatthewJamesDavis是的,我确实相信它是最好的,但是以性能为代价,即如果我有'n'复选框,计算结果将会运行'n'次onload是不是。 – 2014-11-14 19:50:18

1

计算出的方法是正确的方法。您可以通过使用pureComputed并使用rateLimit来改善一些性能问题。两者都需要比您的示例中使用的2.2.1更新版本的Knockout(分别为3.2和3.1)。

self.SelectAll = ko.pureComputed({ 
    read: function() { 
     var item = ko.utils.arrayFirst(self.People(), function(item) { 
      return !item.Selected(); 
     }); 
     return item == null;   
    }, 
    write: function(value) { 
     ko.utils.arrayForEach(self.People(), function (person) { 
      person.Selected(value); 
     }); 
    } 
}).extend({rateLimit:1}); 

http://jsfiddle.net/mbest/AneL9/98/

+0

好的迈克尔我刚刚读了ratelimit的文档。它会延迟将可观察价值更新为最新输入的权利。那么这个ratelimit有没有可能帮助计算出不加载并且在加载后工作。 – 2014-11-15 07:23:52

+0

我希望你能在这里看到更大的图片队友我可能有1000个复选框或更多与数据进来。默认情况下,我将每个复选框绑定为'false',我觉得没有必要计算onLoad再次评估什么要绑定到1000复选框,因为它的错误我提到但计算是真正有用的负载困难之后。 – 2014-11-15 07:30:00

+0

我会使用手动订阅添加另一个答案。 – 2014-11-15 20:13:00