javascript - Knockout change le gestionnaire d'événements



knockout.js durandal (1)

Je passe des heures à essayer de faire fonctionner un appel d'événement simple correctement dans mon application durandal / knockout.

Le contexte

J'ai une liste de langues que l'utilisateur peut sélectionner dans une boîte de sélection:

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

La propriété app.selectedLanguage est un ko.observable. Je sais que cela fonctionne parce que l'article correct est présélectionné.

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

J'ai également un gestionnaire d'événements qui écoute les changements sur cette boîte de sélection, de sorte que je puisse envoyer un message à d'autres parties de l'application qui doivent être informés:

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

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

Le problème

  1. le premier paramètre 'données' ne contient pas l'élément sélectionné, mais contient tous les éléments (en fait, il semble être le modèle de vue actuel complet).
  2. Si 1. ne fonctionne pas, alors ce serait une alternative pour au moins obtenir la nouvelle valeur à partir de la 'langue sélectionnée'. Malheureusement, cela semble toujours avoir l'ancienne valeur. Donc, chaque fois que je change l'option selectbox, j'obtiens toujours la valeur précédemment sélectionnée.

Question

Donc la question est: qu'est-ce que je pourrais faire de mal? Je suis sûr que cela fonctionne normalement et qu'il me manque quelque chose quelque part.

Je pensais avoir enfin compris comment KO fonctionne, mais maintenant je suis tombé sur le prochain numéro. Je serais très reconnaissant si quelqu'un pouvait m'aider à ce sujet.

EDIT [RESOLU]

Grâce à xdumaine, voici la solution (sympa et simple):

Dans mon modèle html, j'ai supprimé l'événement change:

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

Dans mon modèle de vue d'application (que j'ai besoin partout), je m'abonne maintenant à ko.observable au lieu d'écouter le gestionnaire d'événements:

    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;
    });

Ce code a donc été supprimé et n'est plus nécessaire:

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

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

Cordialement, Michael


Pourquoi se lier à l'événement select change au lieu de simplement s'abonner à la langue selected?

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

Si vous voulez le faire comme vous l'avez, sachez ceci: les bindings d'événement dans knockout obtiennent toujours une référence à viewModel comme premier paramètre, et les données d'événement comme seconde, donc vous pourriez devoir inspecter l'événement pour obtenir le ciblez et extrayez la valeur si vous le faites de cette façon. La raison pour laquelle 2 ne fonctionne pas, c'est que votre évènement de changement se déclenche avant que l'observable knockout ne soit notifié, ainsi vous obtenez des problèmes de timing. Cela pourrait avoir un comportement différent dans différents navigateurs.

Je recommande de coller aux abonnements observables, au lieu d'utiliser les événements DOM, autant que possible.





durandal