web-dev-qa-db-fra.com

Comment puis-je obtenir que Knockout JS se mette à lier les données en appuyant sur la touche au lieu de perdre la mise au point?

Cet exemple de knockout js fonctionne lorsque vous modifiez un champ et appuyez sur la touche de tabulation, les données du modèle de vue et, partant, le texte situé sous les champs sont mis à jour.

Comment puis-je modifier ce code pour que les données du modèle de vue soient mises à jour à chaque pression sur une touche?

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>

De la documentation

Paramètres supplémentaires

  • valueUpdate

    Si votre liaison inclut également un paramètre appelé valueUpdate, cela définit l'événement de navigateur que KO doit utiliser pour détecter les modifications. Les valeurs de chaîne suivantes sont les choix les plus utiles:

    • "change" (par défaut) - met à jour votre modèle de vue lorsque l'utilisateur déplace le focus sur un contrôle différent, ou dans le cas d'éléments, immédiatement après toute modification.

    • "keyup" - met à jour votre modèle de vue lorsque l'utilisateur relâche une clé

    • "keypress" - met à jour votre modèle de vue lorsque l'utilisateur a tapé une clé. Contrairement à keyup, cela met à jour à plusieurs reprises pendant que l'utilisateur maintient une touche enfoncée

    • "afterkeydown" - met à jour votre modèle de vue dès que l'utilisateur commence à saisir un caractère. Cela fonctionne en attrapant l'événement keydown du navigateur et en le traitant de manière asynchrone.

Parmi ces options, "afterkeydown" est le meilleur choix si vous souhaitez que votre modèle de vue soit mis à jour en temps réel.

297
Sergei Golos

Dans version 3.2 , vous pouvez simplement utiliser textinput binding. :

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

Il fait deux choses importantes:

  • faire des mises à jour immédiates
  • gère les différences de navigateur pour couper, glisser, complétion automatique ...

Donc, pas besoin de modules supplémentaires, contrôles personnalisés et autres choses.

84
Salvador Dali

Si vous voulez que les mises à jour soient effectuées sur afterkeydown "par défaut", vous pouvez injecter la liaison valueUpdate dans le gestionnaire de liaisons value. Fournissez simplement un nouveau allBindingsAccessor à utiliser par le gestionnaire, qui inclut afterkeydown.

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

Si vous ne vous sentez pas à l'aise pour "écraser" la liaison value, vous pouvez attribuer un nom différent à la liaison personnalisée de substitution et utiliser ce gestionnaire de liaison.

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

démo

Une telle solution conviendrait à Knockout version 2.x. L'équipe Knockout a élaboré une liaison plus complète pour les entrées de type texte via la liaison textInput dans Knockout version 3 et ultérieure. Il a été conçu pour gérer toutes les méthodes de saisie de texte pour les entrées de texte et textarea. Il gérera même les mises à jour en temps réel, ce qui rendra cette approche obsolète.

35
Jeff Mercado

La réponse de Jeff Mercado est fantastique, mais malheureusement cassée avec Knockout 3.

Mais j’ai trouvé la réponse suggérée par les développeurs de ko en travaillant avec les changements de Knockout 3. Voir les commentaires au bas de la page https://github.com/knockout/knockout/pull/932 . Leur 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 a maintenant une solution plus complète avec la nouvelle liaison "textInput". Voir la réponse de SalvidorDali

20
RockResolve