web-dev-qa-db-ja.com

ノックアウト変更イベントハンドラー

デュランダル/ノックアウトアプリで簡単なイベントコールを正しく機能させるために何時間も費やしています。

コンテキスト

ユーザーが選択ボックスから選択できる言語のリストがあります。

    <select class="form-control select2"
        data-bind="event: { change: app.languageChanged }, options:languages,
        optionsText:'label',
        optionsValue:'code',
        value:app.selectedLanguage"></select>

プロパティapp.selectedLanguageはko.observableです。正しいアイテムが事前に選択されているため、これが機能することはわかっています。

    this.selectedLanguage = ko.observable(options.defaultLanguage);

また、その選択ボックスの変更をリッスンするイベントハンドラーがあるので、通知が必要なアプリケーションの他の部分にメッセージを送信できます。

    languageChanged : function(data, event) {
        console.log(data);
        console.log(event);
        console.log(this.selectedLanguage());

        app.trigger('language:change', this.selectedLanguage());
    },

問題

  1. 最初のパラメータ「data」には、選択したアイテムは含まれていませんが、代わりにすべてのアイテムが含まれています(実際には、完全な現在のビューモデルのようです)。
  2. 1.が機能しない場合は、少なくとも監視可能な「selectedLanguage」から新しい値を取得する代わりになります。残念ながら、それは常に古い価値を持っているようです。したがって、selectboxオプションを変更すると、常に以前に選択した値が取得されます。

質問

したがって、質問は次のとおりです。何が間違っている可能性がありますか?これは正常に機能し、どこかに何かが欠けているに違いありません。

ノックアウトの仕組みはようやく理解できたと思いましたが、次の問題に出くわしました。誰かがこれについて私を助けてくれたらとてもありがたいです。

編集[解決済み]

Xdumaineのおかげで、これが(素晴らしくシンプルな)解決策です:

私のhtmlテンプレートで、change-eventを削除しました。

    <select class="form-control select2"
        data-bind="options:languages,
        optionsText:'label',
        optionsValue:'code',
        value:app.selectedLanguage"></select>

私のアプリビューモデル(どこでも必要です)では、イベントハンドラーをリッスンする代わりに、ko.observableをサブスクライブします。

    define([ 'durandal/app', 'underscore', 'knockout', 'myapp/myapp' ], function(app, _, ko, myapp) {

        "use strict";

        function App(options) {

            if (!(this instanceof App)) {
                throw new TypeError("App constructor cannot be called as a function.");
            }

            this.options = options || {};

            // Set the initial language.
            this.selectedLanguage = ko.observable(options.defaultLanguage);
                    // *** Subscribes to the observable ***
            this.selectedLanguage.subscribe(function(newValue) {
                console.log(newValue);
                app.trigger('language:change', newValue);
            });

            _.bindAll(this, 'getSelectedLanguage');
        }

        App.prototype = {
            constructor : App,
            getSelectedLanguage : function() {
                return this.selectedLanguage();
            }
        }

        return App;
    });

したがって、このコードは削除され、不要になりました。

languageChanged : function(data, event) {
    console.log(data);
    console.log(event);
    console.log(this.selectedLanguage());

    app.trigger('language:change', this.selectedLanguage());
},

よろしく、マイケル

12
michaeldd

SelectedLanguageにサブスクライブするだけでなく、select changeイベントにバインドするのはなぜですか?

var self = this;
self.selectedLanguage = ko.observable();
self.selectedLangauge.subscribe(function(newValue) {
    console.log(newValue);
    app.trigger('language:change', newValue);
});

思い通りにやりたい場合は、次のことを知っておいてください。ノックアウトのイベントバインディングは、常に最初のパラメーターとしてviewModelへの参照を取得し、2番目のパラメーターとしてイベントデータを取得するため、イベントを検査して取得する必要があります。そのようにしている場合は、値をターゲットにして抽出します。 2が機能しない理由は、ノックアウトオブザーバブルが通知される前に変更イベントが発生しているため、タイミングの問題が発生するためです。これは、ブラウザによって動作が異なる可能性があります。

可能な限り、DOMイベントを使用するのではなく、監視可能なサブスクリプションに固執することをお勧めします。

18
xdumaine