javascript knockout.js knockout-mapping-plugin knockout-2.0

javascript - Enlace verdadero/falso a los botones de radio en Knockout JS



knockout.js knockout-mapping-plugin (8)

¿Por qué no simplemente verdadero y falso en lugar de 1 y 0?

<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>

En mi opinión, el modelo I tiene un valor IsMale que tiene el valor verdadero o falso.

En mi UI deseo vincularlo a los siguientes botones de opción:

<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>

El problema que creo que está checked espera una cadena "verdadera" / "falsa". Entonces mi pregunta es, ¿cómo puedo obtener este enlace bidireccional con esta UI y modelo?


Después de hacer mucha investigación para una versión anterior de knockout anterior a 3.0, posiblemente haya dos mejores opciones

Crear un extensor knockout como

ko.extenders["booleanValue"] = function (target) { target.formattedValue = ko.computed({ read: function () { if (target() === true) return "True"; else if (target() === false) return "False"; }, write: function (newValue) { if (newValue) { if (newValue === "False") target(false); else if (newValue === "True") target(true); } } }); target.formattedValue(target()); return target; };

Para usar el extensor en su modelo, haría algo como lo siguiente:

function Order() { this.wantsFries= ko.observable(false).extend({ booleanValue: null }); } <span>Do you want fries with that?</span> <label> <input type="radio" name="question" value="True" data-bind="value: wantsFries.formattedValue" /> Yes </label> <label> <input type="radio" name="question" value="False" data-bind="value: wantsFries.formattedValue" /> No </label>

fuente: http://www.timlabonne.com/2013/02/building-a-knockout-js-extender-for-boolean-values/


Esto funciona para mí:

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>


Sé que este es un tema viejo, pero estaba teniendo el mismo problema y descubrí una solución mucho mejor que probablemente se agregó al knockout después de que esta pregunta fuera oficialmente respondida, así que lo dejaré para personas con el mismo problema.

Actualmente no hay necesidad de extensores, manipuladores de enlace personalizados o calculados. Simplemente proporcione una opción "checkedValue", usará eso en lugar del atributo html ''value'', y con eso puede pasar cualquier valor de javascript.

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

O:

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


También puede usar un extender por lo que es fácil reutilizarlos para obtener más observables:

ko.extenders.boolForEditing = function (target, allowNull) { var result = ko.computed({ read: function () { var current = target(); var newValue = null; if (current === undefined || current === null || current === '''') { if (!allowNull) { newValue = ''false''; } } else { newValue = current ? ''true'' : ''false''; } return newValue; }, write: function (newValue) { var current = target(); var valueToWrite = null; if (newValue === undefined || newValue === null || newValue === '''') { if (!allowNull) { valueToWrite = false; } } else { valueToWrite = newValue === ''true''; } // only write if it changed if (valueToWrite !== current) { target(valueToWrite); } else { if (newValue !== current) { target.notifySubscribers(valueToWrite); } } } }).extend({ notify: ''always'' }); result(target()); return result; };

Entonces úsalo así:

this.IsMale.forEditing = this.IsMale.extend({boolForEditing: true});

El parámetro proporcionado a boolForEditing indica si el valor puede ser nulo.

Ver http://jsfiddle.net/G8qs9/1/


Una opción es usar un observable computable escribible .

En este caso, creo que una buena opción es hacer que el observable computable escribible sea "sub-observable" de su IsMale observable. Su modelo de vista se vería así:

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 }); };

Lo vincularías en tu UI como:

<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>

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


Una vez que descubra que la coincidencia inicial del botón de radio solo quiere hacer coincidir una cadena y desea establecer el valor en una cadena, simplemente se trata de convertir su valor inicial en cadena. Tuve que pelear esto con valores Int.

Después de que haya configurado sus observables, convierta el valor en cadena y KO hará su magia desde allí. Si está mapeando con líneas individuales, haga la conversión en esas líneas.

En el código de ejemplo, estoy usando Json para mapear todo el Modelo en un solo comando. Luego, deje que Razor inserte el valor entre las comillas para la conversión.

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>

Utilizo un "Volcar todo en la pantalla" en la parte inferior de mi página web durante el desarrollo.

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

Aquí están los valores de datos, Antes

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

y, después

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

En mi proyecto, no necesité convertir Bools, porque puedo usar una casilla de verificación que no tiene la misma frustración.


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); } } };

Utilice esta carpeta en lugar de crear estúpidos observables computados ko.

Ejemplo:

<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>