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?

42
demandé sur Qaiser Iftikhar 2012-11-03 18:56:09

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

Démo


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

Démo

83
répondu Jeff Mercado 2017-10-24 18:34:32

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/

6
répondu Isaac 2014-02-27 17:49:55

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());​
2
répondu John Earles 2012-11-04 02:06:02

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

0
répondu 7zark7 2012-11-03 17:37:02