Ich frage mich, ob es mit knockoutjs möglich ist, beim Binden Argumente zu übergeben.
Ich binde eine Liste von Ankreuzfeldern und möchte mich an ein einzelnes berechnetes Beobachtungsobjekt in meinem Ansichtsmodell binden. In meinem Ansichtsmodell (basierend auf dem an die Lesefunktion übergebenen Parameter) möchte ich basierend auf bestimmten Bedingungen true/false zurückgeben.
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)" />
Irgendwelche Vorschläge?
Erstellen Sie eine Funktion, deren einziger Zweck darin besteht, eine berechnete Observable zurückzugeben. Es können beliebige Parameter eingegeben werden. Es muss eine separate berechnete Observable sein, wenn Sie möchten, dass es sich um eine bidirektionale Bindung handelt.
Rufen Sie dann in Ihrer Bindung diese Funktion mit den entsprechenden Argumenten auf. Das berechnete beobachtbare Objekt, das es zurückgibt, ist Ihrer Ansicht nach gebunden und wird wie gewohnt aktualisiert.
Hier ist eine Geige wo ich diese Technik zum Erstellen von Ereignishandlern verwendet habe. Sie können hier etwas Ähnliches tun.
Sie können es sauber halten, indem Sie die Funktion zu einer Methode für das Observable machen. Entweder durch Hinzufügen zum ko.observable.fn
Prototyp oder direktes Hinzufügen zur beobachtbaren Instanz.
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);
}
Dann bewerben Sie sich bei Ihrer Ansicht
<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)"/>
Wenn Sie jedoch nur versuchen, alle diese Kontrollkästchen an einen einzelnen Wert in Ihrem Ansichtsmodell zu binden, müssen Sie dies nicht tun. Verwenden Sie die Bindung checked
für ein Array in Ihrem Ansichtsmodell und geben Sie Ihren Kontrollkästchen einen Wert. Jeder aktivierte Wert wird zum Array hinzugefügt. Und es wird eine Zwei-Wege-Bindung sein.
<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([])
};
Die akzeptierte Antwort ist in Ordnung. Wenn Sie jedoch eine Funktion haben, die für jedes Kontrollkästchen eine ko.computed generiert, addieren Sie unnötigen Overhead mit mehreren anonymen berechneten Observablen, was sich schnell summiert, wenn Ihre Kontrollkästchenlisten 4 bis 5 Optionen überschreiten.
Dies ist eine einfachere Implementierung eines bitweisen Szenarios, die berechnete Funktion kann jedoch beliebig sein.
<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>
Skript:
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);
Beispiel Geige hier: http://jsfiddle.net/i_vargas3/RYQgg/
Es gibt keinen Grund, einen computed
-Wert zu verwenden. Definieren Sie einfach eine Funktion in Ihrem Ansichtsmodell und binden Sie das checked
daran.
Unten sehen Sie ein sehr vereinfachtes Beispiel.
-
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());
-
Trotzdem ist es eine gute Idee, so viel Logik wie möglich in Ihr Ansichtsmodell zu pushen. Es ist ratsam, ein Ansichtsmodell zu erstellen, das Ihr Kontrollkästchen als Objekt modelliert, und dann die Logik, ob das Kontrollkästchen aktiviert werden soll, in das Kontrollkästchen einzufügen.
-
EDIT: Aufgrund der Anforderung, eine bidirektionale Bindung durchzuführen, habe ich einen Extender geschrieben, um eine Observable zu verwalten.
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());
Ohne die Einzelheiten zu kennen, scheint es so, als ob Sie einen ko.observableArray- oder einen berechneten Array-Wert definieren sollten
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())
})
und keine Werte aus dem Markup übergeben, um den Modellstatus zu definieren