如何使Knockout JS在按键上进行数据绑定而不是失去焦点?


191

这个敲除js的示例起作用,因此,当您编辑字段并按TAB时,视图模型数据以及字段下方的文本将更新。

如何更改此代码,以便每次按键时更新视图模型数据?

替代文字

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

萨尔瓦多是正确的-它会自动以最新版本进行操作。
vapcguy 2015年

Answers:


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应使用哪个浏览器事件来检测更改。以下字符串值是最常用的选择:

    • “ change”(更改)(默认)-在用户将焦点移至其他控件时(或在使用元素的情况下)更改后立即更新您的视图模型

    • “键”-用户释放键时更新您的视图模型

    • “按键”-当用户键入按键时,更新您的视图模型。与keyup不同,此操​​作在用户按住key时反复更新

    • “ afterkeydown”-用户开始输入字符后立即更新您的视图模型。通过捕获浏览器的keydown事件并异步处理该事件来工作。

在这些选项中,如果要实时更新视图模型,“ afterkeydown”是最佳选择。


9
来自基因敲除.js中的文档://语法“ after <eventname>”表示“在事件后异步运行处理程序” //例如,这对于在浏览器更新控件后捕获“ keydown”事件很有用
约翰·赖特

4
无论如何,有将valueUpdate:'afterkeydown'设置为默认值吗?
亚伦·沙福瓦洛夫

2
对于某些输入框,浏览器将显示“自动填充”值(例如,如果输入字段名为“ firstname”)。从自动填充中选择不适用于“ afterkeydown”。有没有办法抓住这个?
安东

2
@Anton除了自动填充值之外,还应该捕获屏幕上的键盘单击和鼠标粘贴事件。使用afterkeydown是一个不好的解决方案。
John Kurlak

2
此答案的作者,请更新为也包括Salvador Dali的答案,从3.2版本开始添加的textInput是更好的解决方案,因为它与移动浏览器具有更好的兼容性(例如自动完成功能更好)
Michael Crook 2014年

85

3.2版中,您可以简单地使用textinput绑定。

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

它有两件重要的事情:

  • 立即更新
  • 处理浏览器的剪切,拖动,自动完成功能差异...

因此,无需其他模块,自定义控件和其他内容。


这确实很好,并且正是我替换值所需要的:字段,valueUpdate:我通过应用程序都拥有的'input change'... :)谢谢。
Tod Thomson

当用户单击新的HTML5搜索输入字段上的“ x”图标并像输入为空时一样,是否可以捕获事件?
Codrina Valo

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团队通过Knockout版本3及更高版本中的textInput绑定为类文本输入充实了更完整的绑定。它旨在处理所有用于文本输入和的文本输入方法textarea。它甚至可以处理实时更新,从而有效地使这种方法过时了。


2
这样可以使我的标记更简洁。另外,除了“ afterkeydown”之外,还可以添加“ input”和“ paste”事件以处理粘贴/拖放操作。
bob 2013年

在上述解决方案中,我认为“ typeof valueUpdated ==='array'”需要替换为“ Object.prototype.toString.call(valueUpdate)==='[object Array]'”。参见stackoverflow.com/questions/4775722/…–
daveywc

20

杰夫·梅卡多(Jeff Mercado)的回答很棒,但不幸的是被淘汰赛3打破了。

但是我在进行淘汰赛3变更时发现了ko开发人员建议的答案。请参阅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的答案


1
感谢您将答案更新为3.0!
Graham T

KO 3.2中的@GrahamT甚至不需要它。这只是一条线
Salvador Dali

对于那些在KO 3.2上启动时不了解TextInput并且无法更新整个系统中每个输入的人来说,这是非常好的!
cscott530 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.