web-dev-qa-db-ja.com

Knockout JSでフォーカスを失うのではなく、キーを押すとデータバインドできるようにするにはどうすればよいですか?

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

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

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>

ドキュメント から

追加パラメーター

  • valueUpdate

    バインディングにvalueUpdateというパラメーターも含まれている場合、これはKOが変更を検出するために使用するブラウザーイベントを定義します。次の文字列値は、最も一般的に有用な選択肢です。

    • 「変更」(デフォルト)-ユーザーが変更の直後にフォーカスを別のコントロールに移動したとき、または要素の場合はビューモデルを更新します

    • 「キーアップ」-ユーザーがキーを離したときにビューモデルを更新します

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

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

これらのオプションのうち、ビューモデルをリアルタイムで更新したい場合は、「アフターキーダウン」が最良の選択です。

297
Sergei Golos

バージョン3.2では、単に textinput binding。 を使用できます。

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

2つの重要なことを行います。

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

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

84
Salvador Dali

「デフォルトで」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のすべてのテキスト入力メソッドを処理するように設計されています。リアルタイム更新も処理するため、このアプローチは事実上廃止されます。

35
Jeff Mercado

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/

EditKo 3.2.0には、新しい「textInput」バインディングによるより完全なソリューションがあります。 SalvidorDaliの回答をご覧ください

20
RockResolve