Обработчик событий изменения нокаута

Я трачу часы, пытаясь заставить простой вызов событий работать правильно в моем приложении durandal/knockout.

Контекст

У меня есть список языков, которые пользователь может выбрать из окна выбора:

    <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. не работает, то это будет альтернативой, по крайней мере, получить новое значение из наблюдаемого 'selectedLanguage'. К сожалению, это всегда кажется старым. Поэтому всякий раз, когда я меняю опцию selectbox, я всегда получаю ранее выбранное значение.

Вопрос

Итак, вопрос в том, что я могу делать неправильно? Я уверен, что это нормально работает правильно, и я должен что-то пропускать где-то.

Я думал, что наконец понял, как работает нокаут, но теперь я столкнулся с следующей проблемой. Я был бы очень благодарен, если бы кто-нибудь мог мне помочь в этом.

EDIT [SOLVED]

Благодаря xdumaine, это (хорошее и простое) решение:

В моем шаблоне html я удалил событие change:

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

В моей модели приложения App (которую я требую везде), теперь я подписываюсь на 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());
},

С уважением, Майкл

Ответ 1

Зачем связываться с событием select change вместо того, чтобы просто подписываться на выбранный язык?

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

Если вы хотите сделать это, как у вас есть, знайте это: привязки событий в нокауте всегда получают ссылку на viewModel в качестве первого параметра, а данные события - на второй, так что вам может потребоваться проверить событие чтобы получить цель и извлечь значение, если вы это делаете. Причина 2 не работает в том, что ваше событие изменения стреляет до уведомления нокаута, уведомляемого, поэтому вы получаете проблемы с синхронизацией. Это может иметь различное поведение в разных браузерах.

Я рекомендую придерживаться наблюдаемых подписки, а не использовать DOM-события, когда это возможно.