Як я можу заставити Knockout JS до прив’язки даних на натисканні клавіші замість втраченого фокусу?


191

Цей приклад вибивання js працює так, коли ви редагуєте поле і натискаєте TAB, дані перегляду моделей, а отже, текст під полями оновлюється.

Як я можу змінити цей код, щоб дані viewmodel оновлювалися при кожному натисканні клавіші?

alt текст

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

9
У KO 3.2 не потрібно робити усі ці шляхи вирішення: stackoverflow.com/a/25493265/1090562
Сальвадор Далі,

Сальвадор правильний - він робить це автоматично в останній версії.
vapcguy

Відповіді:


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

З документації

Додаткові параметри

  • valueUpdate

    Якщо ваше прив'язка також включає параметр, який називається valueUpdate, це визначає, який подія браузера KO повинен використовувати для виявлення змін. Наступні рядкові значення є найбільш часто корисним вибором:

    • "змінити" (за замовчуванням) - оновлює модель перегляду, коли користувач переміщує фокус на інший елемент керування, або у випадку елементів, одразу після будь-якої зміни

    • "keyup" - оновлює вашу модель перегляду, коли користувач відпускає ключ

    • "натискання клавіші" - оновлює вашу модель перегляду, коли користувач набрав ключ. На відміну від клавіатури, ця програма оновлюється неодноразово, поки користувач утримує клавішу

    • "afterkeydown" - оновлює вашу модель перегляду, як тільки користувач почне вводити символ. Це спрацьовує, перехоплюючи подію клавіші браузера та обробляючи подію асинхронно.

З цих варіантів найкращим вибором є "післязаключення", якщо ви хочете оновлювати модель перегляду в режимі реального часу.


9
з docs в knockout.js: // Синтаксис "після <ім'я>> означає" запустити обробник асинхронно після події "// Це корисно, наприклад, для лову подій" клавішного "після того, як браузер оновив елемент керування
Джон Райт

4
Чи є в будь-якому випадку отримати valueUpdate: 'afterkeydown' за замовчуванням ?
Аарон Шафовалоф

2
у деяких полях введення браузер показує значення "автозаповнення" (наприклад, якщо поле введення називається "ім'ям"). вибір із автоматичного заповнення не працює з "післязаключенням". чи є спосіб це зловити?
Антон

2
@Anton Окрім значень автоматичного заповнення, є також кліки на екрані клавіатури та події вставки миші, які слід виловити. Використання afterkeydown- це погане рішення.
Джон Курлак

2
Автор цієї відповіді, будь ласка, оновіть, щоб також включити відповідь Сальвадора Далі, текстВведення додано станом на 3,2 є кращим рішенням, оскільки вона має кращу сумісність з мобільними браузерами (такі речі, як автоматичне завершення роботи краще)
Майкл Крук

85

У версії 3.2 ви можете просто використовувати введення тексту для введення тексту. :

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

Це робить дві важливі речі:

  • негайно оновлювати
  • обробляє відмінності браузера для вирізання, перетягування, автозаповнення ...

Тому немає необхідності в додаткових модулях, користувацьких елементах управління та інших речах.


Це працює дуже добре і саме те, що мені потрібно було замінити значення: field, valueUpdate: 'зміна вводу', що я мав все через свій додаток ... :) дякую.
Тод Томсон

Чи є спосіб зафіксувати подію, коли користувач натискає на іконку "x" у новому полі введення HTML5 пошуку та діє так, як у випадку, якщо введення порожнє?
Кодріна Вало

35

Якщо ви хочете, щоб оновлення було afterkeydownвиконано "за замовчуванням", ви можете ввести valueUpdateприв'язку в valueоброблювач прив'язки. Просто поставте нове allBindingsAccessorдля обробника для використання, що включає 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
    };
} ());

Якщо вам не зручно "переосмислювати" valueприв'язку, ви можете надати переважному користувальницькому в'язанню інше ім'я та використовувати цей оброблювач прив'язки.

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

демонстрація

Таке рішення підійде для Knockout версії 2.x. Команда Knockout розробила більш повну прив'язку для текступодібних входів через прив'язку textInput у Knockout версії 3 та новіших версій. Він був розроблений для обробки всіх методів введення тексту для введення тексту та textarea. Він навіть оброблятиме оновлення в режимі реального часу, що ефективно робить цей підхід застарілим.


2
Це робить мою розмітку трохи охайнішою. Крім того, крім 'afterkeydown', 'введення' та 'вставити' події можуть бути додані для обробки дій вставлення / перетягування.
боб

У наведеному вище рішенні я думаю, що "typeof valueUpdated === 'масив'" потрібно замінити на "Object.prototype.toString.call (valueUpdate) === '[масив об'єкта]'". Див stackoverflow.com/questions/4775722 / ...
daveywc

20

Відповідь Джеффа Меркадо - фантастична, але, на жаль, зламана з нокаутом 3.

Але я знайшов відповідь, яку запропонували кодекси під час роботи над нокаутом 3 змін. Дивіться основні коментарі на веб- сайті https://github.com/knockout/knockout/pull/932 . Їх код:

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

У редакції Ko 3.2.0 тепер є більш повне рішення з новою прив'язкою "textInput". Дивіться відповідь СальвідорДалі


1
Дякуємо за оновлення відповіді до 3.0!
Грем Т

@GrahamT в KO 3.2 вам це навіть не потрібно. Це лише один рядок
Сальвадор Далі

Дуже приємно для тих, хто з КО 3.2, хто не знав про TextInput, коли ми починали, і не може оновити кожен вхід у всій системі!
cscott530
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.