web-dev-qa-db-de.com

Binden von true / false an Optionsfelder in Knockout JS

In meinem Ansichtsmodell habe ich einen IsMale-Wert, der den Wert true oder false hat.

In meiner Benutzeroberfläche möchte ich es an die folgenden Optionsfelder binden:

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

Ich denke, das Problem ist, dass checked eine Zeichenfolge "true"/"false" erwartet. Meine Frage ist also, wie kann ich diese 2-Wege-Bindung mit dieser Benutzeroberfläche und diesem Modell erhalten?

82
C.J.

Eine Option ist die Verwendung eines beschreibbar, berechnet, beobachtbar .

In diesem Fall denke ich, dass eine Nice-Option darin besteht, das berechnete beschreibbare Observable zu einem "Sub-Observable" Ihres IsMale Observable zu machen. Ihr Ansichtsmodell würde folgendermaßen aussehen:

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

Sie würden es in Ihrer Benutzeroberfläche wie folgt binden:

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

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

79
RP Niemeyer

Ich weiß, dass dies ein alter Thread ist, aber ich hatte das gleiche Problem und fand eine viel bessere Lösung, die wahrscheinlich zu Knockout hinzugefügt wurde, nachdem diese Frage offiziell beantwortet wurde. Daher überlasse ich sie nur Leuten mit demselben Problem.

Derzeit sind keine Extender, benutzerdefinierten Bindungshandler oder Berechnungen erforderlich. Geben Sie einfach eine "checkedValue" -Option an, die anstelle des HTML-Attributs "value" verwendet wird und mit der Sie einen beliebigen Javascript-Wert übergeben können.

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

Oder:

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

Das funktioniert bei mir:

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

Verwenden Sie diesen Ordner, anstatt dumme ko-berechnete Observablen zu erstellen.

Beispiel:

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

Sobald Sie herausgefunden haben, dass die anfängliche Übereinstimmung für das Optionsfeld nur mit einer Zeichenfolge übereinstimmen soll und den Wert auf eine Zeichenfolge festlegen möchten, es geht einfach darum, Ihren anfänglichen Wert in zu konvertieren string. Ich musste das mit Int-Werten bekämpfen.

Nachdem Sie Ihre Observablen eingerichtet haben, konvertieren Sie den Wert in einen String, und KO erledigt seine Aufgabe von dort aus. Wenn Sie mit einzelnen Zeilen mappen, führen Sie die Konvertierung in diesen Zeilen durch.

Im Beispielcode verwende ich Json, um das gesamte Modell in einem einzigen Befehl zuzuordnen. Lassen Sie dann Razor den Wert zwischen den Anführungszeichen für die Konvertierung einfügen.

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>

Ich verwende ein "Dump it all to the screen" am Ende meiner Webseite während der Entwicklung.

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

Hier sind die Datenwerte Vorher

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

und Nachher

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

In meinem Projekt musste ich Bools nicht konvertieren, da ich ein Kontrollkästchen verwenden kann, das nicht die gleiche Frustration aufweist.

1
Greg Little

Sie können auch einen Extender verwenden, um sie für mehr Observables wiederzuverwenden:

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

Dann benutze es so:

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

Der Parameter für boolForEditing gibt an, ob der Wert null sein darf.

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

0
sroes

Warum nicht einfach wahr und falsch statt 1 und 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>
0
Doctor

Nach umfangreichen Recherchen nach älteren Versionen von Knockout vor 3.0 gibt es möglicherweise zwei beste Optionen

Erstellen Sie einen Knockout-Extender wie

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

Um den Extender auf Ihrem Modell zu verwenden, gehen Sie folgendermaßen vor:

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>

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

0
Anshul Nigam