webentwicklung-frage-antwort-db.com.de

Knockoutjs berechnete Übergabeparameter

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?

42
Qaiser Iftikhar

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)"/>

Demo


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([])
};

Demo

84
Jeff Mercado

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/

6
Isaac

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());​
3
John Earles

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

0
7zark7