83 votes

Liaison vrai / faux aux boutons radio de Knockout JS

Dans mon modèle de vue, j'ai une valeur IsMale qui a la valeur true ou false.

Dans mon interface utilisateur, je souhaite l'associer aux boutons radio suivants:

 <label>Male
   <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
</label>
 

Le problème que je pense est checked s'attend à une chaîne "true" / "false". Ma question est donc la suivante: comment puis-je obtenir cette liaison bidirectionnelle avec cette interface utilisateur et ce modèle?

127voto

Natan Points 807

Je sais que c'est un vieux thread, mais j'ai eu le même problème et a trouvé une bien meilleure solution qui a probablement été ajoutée à knock-out après que cette question a été officiellement répondu, donc je vais en laisser pour les personnes avec le même problème.

Actuellement, il n'est pas nécessaire pour les câbles d'extension, de liaison personnalisée gestionnaires ou computeds. Il suffit de fournir un "checkedValue" option, au lieu d'utiliser le code html de la valeur de l'attribut, et avec qui vous pouvez passer n'importe quel javascript valeur.

<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: true"/>
<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: false"/>

Ou:

<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 1"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 2"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 3"/>

80voto

RP Niemeyer Points 81663

Une option est d'utiliser une écriture calculée observables.

Dans ce cas, je pense que c'est un joli option est de faire de l'écriture calculée observables d'un "sous-observables" de votre IsMale observables. Votre modèle de vue ressemblerait à:

var ViewModel = function() {
   this.IsMale = ko.observable(true);

   this.IsMale.ForEditing = ko.computed({
        read: function() {
            return this.IsMale().toString();  
        },
        write: function(newValue) {
             this.IsMale(newValue === "true");
        },
        owner: this        
    });          
};

Vous serait-il lier dans votre INTERFACE utilisateur comme:

<label>Male
   <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale.ForEditing"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale.ForEditing"/>
</label>

Exemple: http://jsfiddle.net/rniemeyer/Pjdse/

10voto

Artem Points 2476

Cela fonctionne pour moi:

http://jsfiddle.net/zrBuL/291/

 <label>Male
   <input type="radio" name="IsMale" value="1" data-bind="checked:IsMale"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="0" data-bind="checked:IsMale"/>
</label>
 

1voto

KurtJ Points 19
 ko.bindingHandlers['radiobuttonyesno'] = {
    'init': function (element, valueAccessor, allBindingsAccessor) {
        var stateHandler = function (property, allBindingsAccessor, key, value, checkIfDifferent) {
            if (!property || !ko.isObservable(property)) {
                var propWriters = allBindingsAccessor()['_ko_property_writers'];
                if (propWriters && propWriters[key])
                    propWriters[key](value);
            } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
                property(value);
            }
        };

        var updateHandler = function () {
            var valueToWrite;

            if ((element.type == "radio") && (element.checked)) {
                valueToWrite = element.value;
            } else {
                return; // "radiobuttonyesno" binding only responds to selected radio buttons
            }

            valueToWrite = (valueToWrite === "True") ? true : false;

            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue); //can be true of false

            stateHandler(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
        };
        ko.utils.registerEventHandler(element, "click", updateHandler);

        // IE 6 won't allow radio buttons to be selected unless they have a name
        if ((element.type == "radio") && !element.name)
            ko.bindingHandlers['uniqueName']['init'](element, function () { return true });
    },
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());

        value = value ? "True" : "False";

        if (element.type == "radio") {
            element.checked = (element.value == value);
        }
    }
};
 

Utilisez ce classeur au lieu de créer de stupides ko observables calculés.

Exemple:

 <label>Male
        <input type="radio" name="IsMale" value="True" data-bind="radiobuttonyesno:IsMale"/>
     </label> 
     <label>Female
        <input type="radio" name="IsMale" value="False" data-bind="radiobuttonyesno:IsMale"/>
     </label>
 

1voto

Greg Little Points 126

Une fois que vous comprendre que le match initial pour le bouton radio veut correspondre qu'à une chaîne et veut régler la valeur à une chaîne, c'est simplement une question de la conversion de votre valeur initiale de la chaîne. J'ai eu à ce combat, avec les valeurs Int.

Après que vous avez configuré votre observables, convertir la valeur de chaîne et KO fera sa magie à partir de là. Si vous êtes à la cartographie avec des lignes individuelles, de faire la conversion dans ces lignes.

Dans l'exemple de code, je suis en utilisant Json pour cartographier l'ensemble du Modèle en une seule commande. Puis en laissant de Rasoir insérer la valeur entre guillemets pour la conversion.

script type="text/javascript">
    KoSetup.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
    KoSetup.ViewModel.ManifestEntered("@Model.ManifestEntered");       //Bool
    KoSetup.ViewModel.OrderStatusID("@Model.OrderStatusID");           //Int
</script>

J'utilise un "Dump tout à l'écran" en bas de ma page web en cours de développement.

<h4>Debug</h4>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

Voici les valeurs de données, Avant d'

"OrderStatusID": 6,
"ManifestEntered": true,

et, Après

"OrderStatusID": "6",
"ManifestEntered": "True",

Dans mon projet, je n'ai pas besoin de convertir des Booléens, parce que je suis en mesure d'utiliser une case à cocher qui n'ont pas la même frustration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X