Richtig/falsch an Optionsfelder in Knockout JS binden

Lesezeit: 8 Minuten

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>

Das Problem ist meiner Meinung nach checked erwartet einen String “true”https://stackoverflow.com/”false”. Meine Frage ist also, wie bekomme ich diese 2-Wege-Bindung mit dieser Benutzeroberfläche und diesem Modell?

  • Für Knockout-Versionen> = 3.0 finden Sie in Natans Antwort eine einfachere Lösung als in der akzeptierten Antwort vorgeschlagen.

    – Markus Pscheidt

    7. Februar 2014 um 20:37 Uhr


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, also überlasse ich es einfach Leuten mit demselben Problem.

Derzeit besteht keine Notwendigkeit für Extender, benutzerdefinierte Bindungshandler oder Berechnungen. Geben Sie einfach eine “checkedValue”-Option an, die anstelle des HTML-Attributs “value” verwendet wird, und damit können Sie jeden Javascript-Wert übergeben.

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

  • Wenn man sich die Quelle ansieht, scheint es eine Entscheidung zu treffen, den überprüften Wert zu verwenden hier. Der ‘useCheckedValue’ wird auf true gesetzt wenn die Eingabe ein Optionsfeld oder ein Kontrollkästchen mit dem Wert als Array ist. Außerdem verwende ich Knockout 3.0. Mal sehen, ob das hilft.

    – Natan

    22. Januar 2014 um 12:50 Uhr


  • Ja, danke, ich habe auf 3.0.0 aktualisiert und jetzt ist es da. Ich muss meine booleschen Werte immer noch in einen String packen, weil der Servercode diese erwartet hat 😉

    – ZiglioUK

    22. Januar 2014 um 21:15 Uhr

  • Gute Infos. Zwei zusätzliche Punkte: (1) Ich habe festgestellt, dass ich mit Pre-v3.0 Knockout die verwenden konnte value Bindung und dann die checked Bindung (in dieser Reihenfolge), aber mit 3.0 musste ich die verwenden checkedValue Bindung statt der value Bindung. (2) Pre-v3.0 war wählerisch, wenn es darum ging, die value verbindlich vor dem checked Binding korrekt zu funktionieren, daher habe ich das Gefühl, dass die Dinge auch in v3.0 in allen Szenarien besser funktionieren könnten, wenn Sie das setzen checkedValue verbindlich vor dem checked Bindung, wie sie in der zeigen Dokumente.

    – Jason Frank

    13. Februar 2014 um 0:35 Uhr

  • @ZiglioNZ Eine Möglichkeit, wie dies fehlschlagen kann, ist, wenn Ihre checked setter (oder vielleicht etwas davon abhängiges) löst einen Fehler aus – dann ist das richtige Kontrollkästchen nicht aktiviert

    – Simon_Weaver

    4. August 2014 um 0:39 Uhr


  • Ich verwende Version 3.4 und finde, dass ich immer noch value=”true” und das Obige eingeben muss, damit es funktioniert.

    – Kabel

    15. Juni 2016 um 17:16 Uhr

Eine Möglichkeit ist die Verwendung von a beschreibbar berechnet beobachtbar.

In diesem Fall denke ich, dass es eine gute Option ist, das beschreibbare berechnete Observable zu einem “Sub-Observable” von Ihnen zu machen IsMale beobachtbar. Ihr Ansichtsmodell würde wie folgt 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>

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

  • Scheint eine tolle Lösung zu sein. Ich verwende das Mapping-Plug-in, um meine VM zu aktualisieren. Kennen Sie es, das ForEditing auf IsMale auslöschen würde?

    – CJ

    12. April 2012 um 16:32 Uhr


  • Hier ist eine Alternative, die die berechnete beobachtbare Erstellung in eine benutzerdefinierte Bindung schiebt, sodass Sie sich nicht darum kümmern müssen, sie im Mapping-Plugin zu behandeln: jsfiddle.net/rniemeyer/utsvJ

    – RP Niemeyer

    12. April 2012 um 17:25 Uhr

  • +1 zur Verwendung einer Bindung, anstatt ein Observable für jedes Objekt zu erstellen

    – Greg Ennis

    29. März 2013 um 3:49 Uhr

  • @RPNiemeyer ist definitiv der richtige Weg.

    – Andreas

    31. Juli 2013 um 21:15 Uhr

  • @RPNiemeyer danke! Diese Geige in den Kommentaren hat bei mir funktioniert.

    – SFlagg

    17. Dezember 2015 um 15:55 Uhr

Benutzer-Avatar
Artem

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>

  • Das einzige Problem, das ich sehe, ist, dass Sie beim Serialisieren von Viewmodel zur Übergabe an den Server Integer in Observable (anstelle von Booleans) erhalten. Sie müssen anrufen vm.IsMale(!!vm.+IsMale()); vor dem Serialisieren von json zum Senden an den Server (falls die Serverseite nicht richtig damit umgehen kann)

    – Artjom

    12. April 2012 um 16:10 Uhr

  • Ich denke, Sie haben Recht, aber meine Javascript-Kenntnisse fehlen. Können Sie mir bitte erklären, wie !!+ funktioniert? Ich bin mit dieser Syntax nicht vertraut.

    – CJ

    12. April 2012 um 16:40 Uhr

  • @CJ dies konvertiert eine Zeichenfolge oder Zahl in einen booleschen Wert – überprüfen Sie dies jsfiddle.net/nickolsky/6ydLZ wenn string bereits bool ist, wird es als bool behalten

    – Artjom

    12. April 2012 um 16:46 Uhr


  • Vielen Dank. Ich finde das auch eine tolle Lösung.

    – CJ

    12. April 2012 um 17:31 Uhr

  • Es funktioniert jedoch nicht in beide Richtungen. Die Optionsfelder werden beim Laden nicht überprüft.

    – Mikael Östberg

    2. Dezember 2013 um 13:27 Uhr

Benutzer-Avatar
KurtJ

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 Binder, anstatt dumme ko-berechnete Observables 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>

Benutzer-Avatar
Gregor Klein

Sobald Sie das herausgefunden haben Die anfängliche Übereinstimmung für das Optionsfeld möchte nur mit einer Zeichenfolge übereinstimmen und möchte den Wert auf einen String setzen, Es ist lediglich eine Frage der Konvertierung Ihres Anfangswerts in eine Zeichenfolge. Ich musste das mit Int-Werten bekämpfen.

Nachdem Sie Ihre Observables eingerichtet haben, konvertieren Sie den Wert in eine Zeichenfolge und KO wird von dort aus seine Magie ausführen. Wenn Sie eine Zuordnung mit einzelnen Zeilen vornehmen, führen Sie die Konvertierung in diesen Zeilen durch.

Im Beispielcode verwende ich Json, um das gesamte Modell in einem einzigen Befehl abzubilden. 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 während der Entwicklung ein “Dump it all to the screen” am Ende meiner Webseite.

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

Hier sind die Datenwerte, Vor

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

und, Nach

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

Benutzer-Avatar
Arzt

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>

Benutzer-Avatar
sroes

Sie können auch eine verwenden Verlängerung Es ist also einfach, sie für weitere 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 verwenden Sie es wie folgt:

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

Der Parameter, der bereitgestellt wird boolForEditing gibt an, ob der Wert null sein darf.

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

1145980cookie-checkRichtig/falsch an Optionsfelder in Knockout JS binden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy