Paramètres de passage calculés
je me demande s'il est possible avec knockoutjs de passer des arguments lors de la liaison.
je suis en train de lier une liste de cases à cocher et je voudrais me lier à un seul calculable observable dans mon viewmodel. Dans mon viewmodel (basé sur le paramètre passé à la fonction read) je veux retourner true/false basé sur certaines conditions.
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)" />
des suggestions?
4 réponses
Créer une fonction dont le seul but est de retourner un calculées observables. Il peut prendre des paramètres comme vous le souhaitez. Il devra être séparé calculée observable si vous voulez qu'il soit une liaison bidirectionnelle.
puis dans votre reliure, appelez cette fonction avec les arguments appropriés. Les retours observables calculés seront liés à dans votre vue et seront mis à jour comme d'habitude.
Ici un violon où j'ai utilisé cette technique pour créer un événement manipulateur. Vous pouvez faire quelque chose de semblable ici.
vous pouvez le garder propre en faisant de la fonction une méthode sur l'observable. Soit par l'ajout de l' ko.observable.fn
prototype ou l'ajouter directement à l'instance observable.
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);
}
puis appliquer à votre vue
<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)"/>
cependant, si vous essayez juste de lier toutes ces cases à cocher à une seule valeur dans votre modèle de vue, vous n'avez pas besoin de faire cela. Utiliser checked
lier un tableau dans votre modèle de vue et donner une valeur à vos cases à cocher. Chaque valeur cochée sera ajoutée au tableau. Et il sera d'une liaison bidirectionnelle.
<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([])
};
la réponse acceptée est correcte, mais si vous avez une fonction qui génère un ko.calculé pour chaque case à cocher, vous ajoutez des frais généraux inutiles avec de multiples observables calculés anonymes, qui s'additionne rapidement lorsque vos listes de cases à cocher dépassent 4-5 options.
il s'agit d'une implémentation plus simple d'un scénario bitwise, mais la fonction computed peut être ce qu'elle doit être.
<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>
Script:
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);
Exemple de violon ici: http://jsfiddle.net/i_vargas3/RYQgg/
Il n'y a pas de raison d'utiliser un computed
valeur. Définissez simplement une fonction dans votre modèle de vue et liez le checked
.
ci-Dessous est un exemple très simpliste.
--
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());
--
cela dit, c'est une bonne idée d'essayer de pousser le plus possible la logique dans votre modèle de vue. Il serait souhaitable de créer un modèle de vue qui modélise votre case à cocher en tant qu'objet, et alors la logique que si la case doit être cochée pourrait être encapsulé à l'intérieur.
--
EDIT: basé sur l'exigence de faire la liaison bidirectionnelle j'ai écrit un extenseur pour gérer un observable.
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());
Sans connaître les détails, il semble comme ce que vous devriez faire est de définir un ko.observableArray ou calculé la matrice de valeur
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())
})
et ne pas passer de valeurs à partir du markup pour définir l'état du modèle