web-dev-qa-db-fra.com

Paramètres de passage calculés par Knockoutjs

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?

42
Qaiser Iftikhar

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

Démo


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

Démo

84
Jeff Mercado

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/

6
Isaac

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

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

0
7zark7