2012-11-03 93 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