Je me demande s'il est possible avec knockoutjs de passer des arguments lors de la liaison.
Je lie une liste de cases à cocher et je voudrais me lier à un seul observable calculé dans mon viewmodel. Dans mon viewmodel (basé sur le paramètre passé à la fonction de lecture), je veux retourner vrai/faux en fonction de 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)" />
Aucune suggestion?
Créez une fonction dont le seul but est de renvoyer un observable calculé. Il peut prendre des paramètres comme vous le souhaitez. Il devra être un observable calculé séparé si vous voulez qu'il s'agisse d'une liaison bidirectionnelle.
Ensuite, dans votre liaison, appelez cette fonction avec les arguments appropriés. L'observable calculé qu'il renvoie sera lié à votre vue et sera mis à jour comme d'habitude.
Voici n violon où j'ai utilisé cette technique pour créer des gestionnaires d'événements. Vous pouvez faire quelque chose de similaire ici.
Vous pouvez le garder propre en faisant de la fonction une méthode sur l'observable. Soit en ajoutant au ko.observable.fn
prototype ou en l'ajoutant 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);
}
Appliquez ensuite à 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 simplement de lier toutes ces cases à cocher à une seule valeur dans votre modèle de vue, vous n'avez pas besoin de le faire. Utilisez la liaison checked
sur un tableau dans votre modèle de vue et attribuez une valeur à vos cases à cocher. Chaque valeur vérifiée sera ajoutée au tableau. Et ce sera une liaison à double sens.
<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 décente, mais si vous avez une fonction qui génère un ko.computed pour chaque case à cocher, vous ajoutez des frais généraux inutiles avec plusieurs observables calculés anonymes, qui s'additionnent 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 au niveau du bit, mais la fonction calculée peut être ce qui 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>
Scénario:
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 aucune raison d'utiliser une valeur computed
. Définissez simplement une fonction dans votre modèle de vue et liez le checked
à celui-ci.
Voici 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 étant dit, c'est une bonne idée d'essayer de pousser autant de logique que possible dans votre modèle de vue. Il serait conseillé de créer un modèle de vue qui modélise votre case à cocher en tant qu'objet, puis la logique de savoir si la case à cocher doit être cochée pourrait être encapsulée à l'intérieur.
-
EDIT: Basé sur l'exigence de faire une liaison bidirectionnelle, j'ai écrit un extender 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 que ce que vous devriez faire soit définir un ko.observableArray ou une valeur de tableau calculée
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 transmettre de valeurs à partir du balisage pour définir l'état du modèle