2012-11-03 97 views
41

我想知道是否有可能與knockoutjs綁定時傳遞參數。Knockoutjs計算傳遞參數

我綁定了一個複選框列表,並希望綁定到我的viewmodel中的單個計算的observable。在我的viewmodel中(基於傳遞給read函數的參數),我想根據某些條件返回true/false。

var myViewModel=function(){ 
    this.myprop=ko.computed({read: function(){ 
    //would like to receive an argument here to do my logic and return based on argument. 
} 
}); 
}; 

<input type="checkbox" data-bind="checked: myprop(someval1)" /> 
<input type="checkbox" data-bind="checked: myprop(someval2)" /> 
<input type="checkbox" data-bind="checked: myprop(someval3)" /> 

有什麼建議嗎?

回答

81

創建其唯一的目的是返回一個計算觀察到的一個功能。它可能需要參數。如果你希望它是一個雙向綁定,它必須是一個單獨的計算觀察值。

然後在你的綁定中,用適當的參數調用該函數。它返回的計算的觀察值將被綁定到你的視圖中,並且將像往常一樣更新。

這裏是a fiddle我用這種技術來創建事件處理程序。你可以在這裏做類似的事情。

通過使該函數成爲observable上的方法,您可以保持清潔。通過添加到ko.observable.fn原型或直接將其添加到可觀察的實例。

ko.observable.fn.bit = function (bit) { 
    return ko.computed({ 
     read: function() { 
      return !!(this() & bit); 
     }, 
     write: function (checked) { 
      if (checked) 
       this(this() | bit); 
      else 
       this(this() & ~bit); 
     } 
    }, this); 
}; 
// or 
function ViewModel() { 
    this.flags = ko.observable(0); 

    this.flags.bit = function (bit) { 
     return ko.computed({ 
      read: function() { 
       return !!(this() & bit); 
      }, 
      write: function (checked) { 
       if (checked) 
        this(this() | bit); 
       else 
        this(this() & ~bit); 
      } 
     }, this); 
    }.bind(this.flags); 
}  

然後應用到你的觀點

<input type="checkbox" data-bind="checked: flags.bit(0x1)"/> 
<input type="checkbox" data-bind="checked: flags.bit(0x2)"/> 
<input type="checkbox" data-bind="checked: flags.bit(0x4)"/> 
<input type="checkbox" data-bind="checked: flags.bit(0x8)"/> 

Demo


然而,如果你只是想所有這些複選框可以將單個值綁定在你的視圖模型,你不」不需要那樣做。在您的視圖模型的數組上使用checked綁定,並給您的複選框一個值。每個選中的值將被添加到數組中。這將是一個雙向綁定。

<input type="checkbox" data-bind="checked: checkedValues, value: 1"/> 
<input type="checkbox" data-bind="checked: checkedValues, value: 2"/> 
<input type="checkbox" data-bind="checked: checkedValues, value: 3"/> 
<input type="checkbox" data-bind="checked: checkedValues, value: 4"/> 
var viewModel = { 
    checkedValues: ko.observableArray([]) 
}; 

Demo

+1

謝謝,這是非常好的。正是我在找什麼。 –

0

不知道的細節,它看起來像什麼,你應該做的是定義一個ko.observableArray或計算陣列值

HTML:

myprop: <input data-bind="value: myprop"> 
<div data-bind="foreach: selections"> 
    <label> 
    <span data-bind="text: value"></span> 
    <input type="checkbox" data-bind="checked: selected"/> 
    </label> 
</div> 

JS:

$(function() { 
    function Model() { 
     this.self = this 
     self.myprop = ko.observable(14) 
     self.bits = [1, 2, 4, 8, 16, 32, 64, 128] 
     self.selections = ko.computed(function() { 
      return self.bits.map(function(bit) { 
       console.log(myprop() & bit) 
       return { 
        value: bit, 
        selected: (myprop() & bit) == bit 
       } 
      }) 
     }) 
    } 

    ko.applyBindings(new Model()) 
}) 

和不通過標記中的值來定義模型狀態

+0

好的建議,不知道這是否會爲我的情況下工作。我的屬性是一個按位標誌,並且基於任何被選中的複選框,它需要影響列表中的其他複選框。不知道是否我正在設法正確地解釋我的情況:( –

+0

)讓我試着解釋一下,說myprop = 14,我有三個複選框,它們的值是2,4,8。如果我改變myprop = 2,在這種情況下,只需要檢查第一個複選框,其餘的兩個需要不選中。 –

+0

請看上面編輯過的例子John的方法也可以,但是更喜歡模型中的邏輯和數據,而不是標記中的參數 – 7zark7

2

有沒有理由使用computed值。只需在您的View Model中定義一個功能,並將其綁定到checked即可。

下面是一個非常簡單的例子。

-

HTML

<input type="checkbox" data-bind="checked: isEven(1)" /> 
<input type="checkbox" data-bind="checked: isEven(2)" /> 
<input type="checkbox" data-bind="checked: isEven(3)" />​ 

JS

var MyViewModel=function(){ 
    this.isEven = function(num) { 
     return (num % 2) == 0; 
    }; 
}; 
ko.applyBindings(new MyViewModel()); 

-

話雖這麼說,這是一個好主意,試圖推動儘可能多的邏輯儘可能進入你的視圖模型。建議您創建一個視圖模型,將您的複選框建模爲對象,然後確定是否應該檢查複選框的邏輯可以封裝在內部。

-

編輯:基於做雙向綁定我寫一個擴展來管理可觀察的要求。

http://jsfiddle.net/jearles/j6zLW/5/

ko.extenders.bitwise = function(target, bitCount) { 
    target.bits = [];  
    target.checked = ko.observableArray(); 

    // Create bit array based on requested number of bits 
    for (i=bitCount-1; i>=0; i--) { 
     target.bits.push(''+Math.pow(2, i)); 
    }   

    // Define a function to create bits 
    function makeBits(newValue) { 
     var num = !isNaN(newValue) ? parseInt(newValue) : 0; 
     var arr = []; 
     for (i=0; i<target.bits.length; i++) { 
      var bitValue = parseInt(target.bits[i]); 
      if ((num & bitValue) == bitValue) arr.push(target.bits[i]); 
     } 
     target.checked(arr); 
    } 

    // Define a function to combine bits 
    function makeBitwise(newBits) { 
     var num = 0; 
     for (i=0; i<target.bits.length; i++) { 
     if (newBits.indexOf(target.bits[i]) > -1) num += parseInt(target.bits[i]); 
     } 
     target(num); 
    } 

    // Create initial bits 
    makeBits(target()); 

    // Make bits whenever the value changes 
    target.subscribe(makeBits); 

    // Make number whenever the bits change 
    target.checked.subscribe(makeBitwise); 

    // Return the original observable 
    return target; 
}; 

var MyViewModel=function(){ 
    var self = this; 
    this.number = ko.observable(2).extend({ bitwise: 8}); 

}; 
ko.applyBindings(new MyViewModel());​ 
+0

感謝您的回覆,但是它的作用就像一次性裝訂,不是嗎?如果值改變了,我怎麼能從viewModel中將變化推回複選框?此外,當複選框的選中狀態發生變化時,我如何更新我的視圖模型? –

+0

這取決於你需要做什麼。看看這個小提琴:http://jsfiddle.net/jearles/j6zLW/ –

+0

謝謝你的小提琴!這非常接近我所需要的。任何想法爲什麼是當您檢查/取消選中UI中的複選框時不調用函數isSet? –

6

接受的答案是體面的,但如果你有生成ko.computed每個複選框的功能,要添加多個匿名計算的觀測不必要的開銷,當您的複選框列表超過4-5個選項時,它會快速加起來。

這是一個比較簡單的按位場景實現,但計算的函數可以是任何需要的。

<input type="checkbox" data-bind="checked: checkedList, value: 1" /> 
<label>Value 1</label> 
<input type="checkbox" data-bind="checked: checkedList, value: 2" /> 
<label>Value 2</label> 
<input type="checkbox" data-bind="checked: checkedList, value: 4" /> 
<label>Value 4</label> 
<input type="checkbox" data-bind="checked: checkedList, value: 8" /> 
<label>Value 8</label> 

腳本:

var vm = function() { 
    var vm = this; 

    this.checkedList = ko.observableArray(); 
    this.bitwiseValue = ko.computed({ 
     read: function() { 
      return vm.checkedList().reduce(function (prev, curr) { 
       return prev | curr; 
      }, 0); 
     }, 
     write: function (myVal) { 
      vm.checkedList.removeAll(); 
      var placeValue = 1; 

      while(myVal > 0) { 
       if((myVal % 2) == 1) { 
        alert(placeValue); 
        vm.checkedList.push(placeValue.toString()); 
       } 

       myVal = myVal >>> 1;      
       placeValue = placeValue * 2; 
      } 
     } 
    }, this); 
} 

ko.applyBindings(vm); 

例小提琴這裏:http://jsfiddle.net/i_vargas3/RYQgg/

+0

這很好,謝謝。但是,如果我分配一個值到bitwiseValue它不檢查它應該在哪裏。有什麼建議麼? – Grandizer

+0

在示例小提琴中,您必須按Return才能進行更改。我修改了綁定,在輸入 – Isaac

+0

上包含'valueUpdate'條目,這真是非常感謝!這裏是最後一個問題,好像添加vm.bitwiseValue(6);在applyBindings之前不會檢查任何關閉的盒子。有沒有辦法將它設置爲從數據庫獲得值? – Grandizer