Как я могу заставить Knockout JS связываться с данными при нажатии клавиши вместо потерянного фокуса?
Этот пример knockout js работает, поэтому, когда вы редактируете поле и нажимаете TAB, обновляются данные viewmodel и, следовательно, текст под полями.
Как я могу изменить этот код, чтобы обновлять данные в режиме viewmodel каждое нажатие клавиши?
![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>
Ответы
Ответ 1
<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>
Из documentation
Дополнительные параметры
-
valueUpdate
Если ваша привязка также включает параметр с именем valueUpdate, это определяет, какое событие KO браузера следует использовать для обнаружения изменений. следующие строковые значения являются наиболее часто используемыми вариантами:
-
"change" (по умолчанию) - обновляет вашу модель представления, когда пользователь перемещает фокус на другой элемент управления или в случае элементы, сразу после любого изменения
-
"keyup" - обновляет вашу модель представления, когда пользователь отпускает ключ
-
"keypress" - обновляет вашу модель представления, когда пользователь набрал ключ. В отличие от keyup, это несколько раз обновляется, пока пользователь держит ключ вниз
- "afterkeydown" - обновляет вашу модель представления, как только пользователь начинает печатать символ. Это работает, ловя браузеры события keydown и обработки события асинхронно.
Из этих опций "afterkeydown" - лучший выбор, если вы хотите обновите свою модель просмотра в режиме реального времени.
Ответ 2
В версии 3.2 вы можете просто использовать привязку textinput.:
<input data-bind="textInput: userName" />
Он выполняет две важные вещи:
- сделать немедленные обновления
- обрабатывает различия браузера для вырезания, перетаскивания, автозаполнения...
Так что нет необходимости в дополнительных модулях, настраиваемых элементах управления и других вещах.
Ответ 3
Если вы хотите, чтобы он выполнял обновления на 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':... };
демо
Такое решение было бы подходящим для нокаута версии 2.x. Команда Knockout создала более полную привязку для текстовых входов через привязку textInput в нокаут версии 3 и выше. Он был разработан для обработки всех методов ввода текста для ввода текста и textarea
. Он даже обрабатывает обновление в реальном времени, что фактически делает этот подход устаревшим.
Ответ 4
Ответ Джеффа Меркадо фантастический, но, к сожалению, сломанный нокаут 3.
Но я нашел ответ, предложенный разработчиками ko при работе с изменениями Knockout 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/
Edit
Ko 3.2.0 теперь имеет более полное решение с новой привязкой "textInput". См. Ответ SalvidorDali