wake-up-neo.net

Wie kann ich Knockout JS dazu bringen, bei Tastendruck Daten zu binden, anstatt den Fokus zu verlieren?

Dieses Beispiel für knockout js funktioniert, wenn Sie ein Feld bearbeiten und die Tabulatortaste drücken, werden die Ansichtsmodelldaten und damit der Text unter den Feldern aktualisiert.

Wie kann ich diesen Code ändern, damit die Ansichtsmodelldaten bei jedem Tastendruck aktualisiert werden?

alt text

<!doctype html>
<html>
    <title>knockout js</title>
    <head>
        <script type="text/javascript" src="js/knockout-1.1.1.debug.js"></script>
        <script type="text/javascript">
        window.onload= function() {

            var viewModel = {
                firstName : ko.observable("Jim"),
                lastName : ko.observable("Smith")
            };
            viewModel.fullName = ko.dependentObservable(function () {
                return viewModel.firstName() + " " + viewModel.lastName();
            });

            ko.applyBindings(viewModel);
       }
        </script>
    </head>
    <body>
        <p>First name: <input data-bind="value: firstName" /></p>
        <p>Last name: <input data-bind="value: lastName" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
    </body>
</html>
189
Edward Tanguay
<body>
        <p>First name: <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></p>
        <p>Last name: <input data-bind="value: lastName, valueUpdate: 'afterkeydown'" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
</body>

Aus der Dokumentation

Zusätzliche Parameter

  • valueUpdate

    Wenn Ihre Bindung auch einen Parameter mit dem Namen valueUpdate enthält, wird hiermit festgelegt, welches Browserereignis KO zum Erkennen von Änderungen verwenden soll. Die folgenden Zeichenfolgenwerte sind die am häufigsten verwendeten Optionen:

    • "change" (Standardeinstellung) - Aktualisiert Ihr Ansichtsmodell, wenn der Benutzer den Fokus auf ein anderes Steuerelement oder bei Elementen unmittelbar nach einer Änderung verschiebt

    • "keyup" - Aktualisiert Ihr Ansichtsmodell, wenn der Benutzer einen Schlüssel freigibt

    • "Tastendruck" - Aktualisiert Ihr Ansichtsmodell, wenn der Benutzer eine Taste eingegeben hat. Im Gegensatz zu keyup wird dies wiederholt aktualisiert, während der Benutzer eine Taste gedrückt hält

    • "afterkeydown" - aktualisiert Ihr Ansichtsmodell, sobald der Benutzer ein Zeichen eingibt. Dies funktioniert, indem das Keydown-Ereignis des Browsers abgefangen und das Ereignis asynchron behandelt wird.

Von diesen Optionen ist "Afterkeydown" die beste Wahl, wenn Sie Ihr Ansichtsmodell in Echtzeit aktualisieren möchten.

297
Sergei Golos

In Version 3.2 können Sie einfach Texteingabebindung verwenden. :

<input data-bind="textInput: userName" />

Es macht zwei wichtige Dinge:

  • sofortige Updates vornehmen
  • behandelt Browserunterschiede für Ausschneiden, Ziehen, Autovervollständigen ...

Es sind also keine zusätzlichen Module, benutzerdefinierten Steuerelemente und andere Dinge erforderlich.

84
Salvador Dali

Wenn Sie möchten, dass Aktualisierungen für afterkeydown "standardmäßig" durchgeführt werden, können Sie die Bindung valueUpdate in den Bindungshandler value einfügen. Geben Sie einfach ein neues allBindingsAccessor für den Handler an, das afterkeydown enthält.

(function () {
    var valueHandler = ko.bindingHandlers.value;
    var getInjectValueUpdate = function (allBindingsAccessor) {
        var AFTERKEYDOWN = 'afterkeydown';
        return function () {
            var allBindings = ko.utils.extend({}, allBindingsAccessor()),
                valueUpdate = allBindings.valueUpdate;

            if (valueUpdate === undefined) {
                return ko.utils.extend(allBindings, { valueUpdate: AFTERKEYDOWN });
            } else if (typeof valueUpdate === 'string' && valueUpdate !== AFTERKEYDOWN) {
                return ko.utils.extend(allBindings, { valueUpdate: [valueUpdate, AFTERKEYDOWN] });
            } else if (typeof valueUpdate === 'array' && ko.utils.arrayIndexOf(valueUpdate, AFTERKEYDOWN) === -1) {
                valueUpdate = ko.utils.arrayPushAll([AFTERKEYDOWN], valueUpdate);
                return ko.utils.extend(allBindings, {valueUpdate: valueUpdate});
            }
            return allBindings;
        };
    };
    ko.bindingHandlers.value = {
        // only needed for init
        'init': function (element, valueAccessor, allBindingsAccessor) {
            allBindingsAccessor = getInjectValueUpdate(allBindingsAccessor);
            return valueHandler.init(element, valueAccessor, allBindingsAccessor);
        },
        'update': valueHandler.update
    };
} ());

Wenn Sie die Bindung value nicht "überschreiben" möchten, können Sie der überschreibenden benutzerdefinierten Bindung einen anderen Namen geben und diesen Bindungshandler verwenden.

ko.bindingHandlers.realtimeValue = { 'init':..., 'update':... };

Demo

Eine solche Lösung wäre für die Knockout-Version 2.x geeignet. Das Knockout-Team hat eine vollständigere Bindung für textähnliche Eingaben durch die Bindung textInput in Knockout Version 3 und höher erstellt. Es wurde entwickelt, um alle Texteingabemethoden für Texteingaben und textarea zu verarbeiten. Es kann sogar in Echtzeit aktualisiert werden, was diesen Ansatz praktisch überflüssig macht.

35
Jeff Mercado

Jeff Mercados Antwort ist fantastisch, aber leider mit Knockout 3 gebrochen.

Aber ich habe die von den Ko-Entwicklern vorgeschlagene Antwort gefunden, als ich Knockout 3-Änderungen durchgearbeitet habe. Siehe die unteren Kommentare unter https://github.com/knockout/knockout/pull/932 . Ihr Code:

//automatically add valueUpdate="afterkeydown" on every value binding
(function () {
    var getInjectValueUpdate = function (allBindings) {
        return {
            has: function (bindingKey) {
                return (bindingKey == 'valueUpdate') || allBindings.has(bindingKey);
            },
            get: function (bindingKey) {
                var binding = allBindings.get(bindingKey);
                if (bindingKey == 'valueUpdate') {
                    binding = binding ? [].concat(binding, 'afterkeydown') : 'afterkeydown';
                }
                return binding;
            }
        };
    };

    var valueInitHandler = ko.bindingHandlers.value.init;
    ko.bindingHandlers.value.init = function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        return valueInitHandler(element, valueAccessor, getInjectValueUpdate(allBindings), viewModel, bindingContext);
    };
}());

http://jsfiddle.net/mbest/GKJnt/

Edit Ko 3.2.0 hat jetzt eine vollständigere Lösung mit der neuen Bindung "textInput". Siehe SalvidorDalis Antwort

20
RockResolve