2014-11-14 67 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