フォーカスを失う代わりに、Knockout JSをキープレスでデータバインドする方法を教えてください。


191

このノックアウトjsの例は機能するため、フィールドを編集してTabキーを押すと、viewmodelデータ、したがってフィールドの下のテキストが更新されます。

このコードを変更して、viewmodelデータがキーを押すたびに更新されるようにするにはどうすればよいですか?

代替テキスト

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

サルバドールは正しいです-最新バージョンでは自動的に行われます。
vapcguy 2015年

回答:


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"-ユーザーがキーを離したときにビューモデルを更新します

    • "keypress"-ユーザーがキーを入力したときにビューモデルを更新します。キーアップとは異なり、ユーザーがキーを押している間、これは繰り返し更新されます

    • "afterkeydown"-ユーザーが文字の入力を開始するとすぐにビューモデルを更新します。これは、ブラウザーのkeydownイベントをキャッチし、イベントを非同期的に処理することで機能します。

これらのオプションのうち、ビューモデルをリアルタイムで更新しておきたい場合は、「afterkeydown」が最適です。


9
knockout.jsのドキュメントから://構文「after <eventname>」は「イベントの後でハンドラーを非同期的に実行する」ことを意味します//これは、たとえば、ブラウザーがコントロールを更新した後に「keydown」イベントをキャッチするのに役立ちます
John Wright

4
valueUpdate: 'afterkeydown'をデフォルトにする方法はありますか?
アーロンシャフォヴァロフ2012

2
一部の入力ボックスでは、ブラウザに「自動入力」値が表示されます(入力フィールドの名前が「firstname」の場合と同様)。自動入力から選択すると、「afterkeydown」では機能しません。これをキャッチする方法はありますか?
アントン

2
@Anton自動入力値に加えて、キャッチする必要のある画面上のキーボードクリックとマウスペーストイベントもあります。使用afterkeydownは悪い解決策です。
John

2
この回答の作成者は、サルバドールダリの回答も含めるように更新してください。3.2の時点で追加されたtextInputは、モバイルブラウザーとの互換性が優れているため、より優れたソリューションです(オートコンプリート作業のようなもの)
Michael Crook

85

バージョン3.2では、単純にtextinputバインディングを使用できます

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

それは2つの重要なことをします:

  • すぐに更新する
  • ブラウザの切り取り、ドラッグ、オートコンプリートの違いを処理します...

そのため、追加のモジュール、カスタムコントロールなどは必要ありません。


これは本当にうまく機能し、私が値を置き換えるために必要なものです:フィールド、値の更新:私がすべてのアプリを通して持っていた '入力の変更' ... :)ありがとう。
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」イベントを追加して、貼り付け/ドラッグアンドドロップアクションを処理できます。
ボブ2013

上記のソリューションでは、「typeof valueUpdated === 'array'」を「Object.prototype.toString.call(valueUpdate)=== '[object Array]'」に置き換える必要があると思います。stackoverflow.com/questions/4775722/…を
daveywc 2013年

20

Jeff Mercadoの答えは素晴らしいですが、残念ながらKnockout 3で破られました。

しかし、Knockout 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への回答を更新していただきありがとうございます。
グラハムT

KO 3.2の@GrahamTでは、必要もありません。たった1行です
サルバドールダリ

KO 3.2を使用していて、起動時にTextInputを知らず、システム全体のすべての入力を更新できない人にとっては非常に便利です。
cscott530 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.