36 votes

Knockout.js semble brouiller mes gestionnaires d'événements jQuery, quelle impolitesse

Ok, j'ai essayé de démêler ce gâchis pour quelques heures maintenant et ont obtenu nulle part, analogue à un chien court après sa queue. Voici la situation.

Je suis à l'aide d'Knockout.js pour mon UI, qui fonctionne très bien par lui-même. Cependant, je suis en train d'utiliser la troisième partie du code qui fait des listes déroulantes et des cases à cocher pour un look de jolie. En fait, je ne suis même pas sûr si c'est un tiers de la bibliothèque ou tout simplement quelque chose de nos designers a écrit. Ce code se cache la vraie case à cocher et le remplace par un faux <span /> qui imite une case à cocher par CSS. L' click événement de la durée de déclencheurs de l' change cas de la vraie case à cocher:

// this code updates the fake UI
this._changeEvent = function() {
    self.isChecked = self.$input.is(':checked');
    self._updateHTML(false, true);
    jQuery(self).trigger('change');
};

// when the user clicks the fake checkbox, we trigger change on the real checkbox
this.$fake.on('click', function(e) {
    e.preventDefault();
    self.$input.click().trigger('change');
});

// Bind _changeEvent to the real checkbox
this.$input.change(this._changeEvent);

Cela fonctionne avec Knockout.js depuis knock-out sera à l'écoute de ce gestionnaire d'événement. En d'autres termes, lorsque l'utilisateur clique sur le faux case, le knock-out lié modèle est mis à jour. Cependant, ce n'est pas le travail est la mise à jour du modèle. Si je l'appelle:

model.SomeValue(!curValue); // SomeValue is bound to a checkbox, flip its value

Le modèle est mis à jour, mais le faux de l'INTERFACE utilisateur n'est pas mis à jour. J'ai tracé ce problème pour le code en ko.bindingHandlers.checked.update qui effectue les opérations suivantes:

// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;

Fondamentalement, l' element.checked propriété est définie, mais pas les événements sont déclenchés. Ainsi, l' _changeEvent fonction n'est jamais appelée. Donc, j'ai mis en place mon propre ko.bindingHandlers.checked.update de la fonction, qui est une copie de l'intégré. En théorie, c'est tout ce que je besoin de le faire:

   ko.bindingHandlers.checked.update = function (element, valueAccessor)
   {
      var value = ko.utils.unwrapObservable(valueAccessor());

      if (element.type == "checkbox")
      {
         if (value instanceof Array)
         {
            // When bound to an array, the checkbox being checked represents its value being present in that array
            element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
         }
         else
         {
            // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
            //element.checked = value;
            $(element).prop('checked', value).trigger('change'); // <--- this should work!
         }
      }
      else if (element.type == "radio")
      {
         element.checked = (element.value == value);
      }
   };

Plutôt que de fixer element.checked, j'ai plutôt appel .prop('checked', value) et de déclencher le changement de l'événement. Toutefois, cela ne fonctionne pas. Voici ce que je sais:

  1. Si je supprime Knockout.js à partir de l'équation, $(element).prop('checked', value).trigger('change'); fonctionne parfaitement bien. Donc, knockout.js est vissage avec l'événement d'une façon. Est-il délier de ce gestionnaire d'événement?
  2. J'ai confirmé $(element) est la même chose que this.$input dans le faux case code de liaison. Je peux mettre d'autres expando les propriétés de cet élément, et qu'ils se présentent.
  3. J'ai tenté quelques approches pour essayer de déboguer dans Knockout.js et jQuery pour voir si l'événement est encore lié, cependant, je n'ai pas vraiment obtenu de n'importe où avec cette approche. Mon intuition est que Knockout.js en quelque sorte remplacé l' change gestionnaire d'événement avec son propre interne, et les liaisons existantes ont été supprimées. Je n'ai pas trouvé un moyen de le confirmer encore.

Ma Question: Principalement, je suis à la recherche d'une solution à ce problème. N'Knockout.js supprimer existants change événements qui étaient là avant, le modèle a été appliqué? Quelles sont les prochaines étapes dans le débogage de ce code et de comprendre exactement ce qui se passe?

2voto

badsyntax Points 4441

Au lieu d'écraser la base vérifié gestionnaire, il suffit de créer votre propre personnalisé contraignantes pour mettre à jour l'INTERFACE utilisateur.

Voici un exemple d'un modèle et d'une liaison personnalisée pour gérer la mise à jour de l'INTERFACE utilisateur:

var Model = function () {
    this.checked = ko.observable(false);
};

ko.bindingHandlers.customCheckbox = {
    init: function (element) {
        // Create the custom checkbox here
        $(element).customInput();
    },
    update: function (element) {
        // Update the checkbox UI after the value in the model changes
        $(element).trigger('updateState');
    }
};

Je vais lier le modèle pour le code HTML suivant:

<input type="checkbox" name="genre" id="check-1" value="action" data-bind="checked: checked, customCheckbox: checked" />

Et vraiment c'est tout ce que je vais avoir à faire.

Voici un exemple: http://jsfiddle.net/badsyntax/4Cy3y/

[edit] - je pense que je me suis précipité à travers la lecture de votre question et ne pas obtenir le point crucial de ce que vous demandez. Je vais laisser ma réponse ici en tout cas.

0voto

Hugo Silva Points 868

Essayez de déclencher et d’écouter également un événement personnalisé:

 element.checked = value;
element.dispatchEvent(new Event("forcedChange"));
 

0voto

Mark Hagers Points 36

Essayez de créer la case à cocher de l'objet en tant que plugin jQuery et créer knock-out liaisons personnalisées pour la lier à vos viewmodel. J'ai mis en place un jsfiddle qui ne fonctionne tout simplement que: http://jsfiddle.net/markhagers/zee4z/3/

$(function () {
    var viewModel = {
        truthyValue1: ko.observable(false),
        truthyValue2: ko.observable(true)
    };

    ko.applyBindings(viewModel);
});

(J'ai dû ajouter cet extrait de code, ou ma réponse n'a pas été acceptée, voir le jsfiddle pour le code complet de l'exemple). Désolé, il semble que beaucoup de code, mais le plugin partie était à l'origine un autonome plugin jquery, avec le knock-out liaisons ajouté plus tard, une partie du code a été rendu obsolète par le knock-out de liaisons. Il peut être placé dans son propre fichier pour réduire l'encombrement. La création de liaisons personnalisées est documenté sur le knock-out du site web.

0voto

Brett Points 1998

Juste un brainstorming, mais ce contrôle tiers a-t-il été développé en utilisant des espaces de noms d'événements? Cela pourrait être comme vous le suggérez, que KO et ce contrôle se disputent d'une manière ou d'une autre l'événement de changement. Lorsque je développe des widgets et des applications, j'utilise toujours des espaces de nom d'événement lors de la liaison d'événements à l'aide de jQuery.

Exemple utilisant un espace de noms 'myWidget':

 $('#element').on('change.myWidget', function(e) {
  // handle the event
}
 

Je pourrais être complètement hors de la base si.

0voto

Jari Points 67

Juste une pensée rapide. Vos concepteurs semble déclencher le et cliquez sur modifier l'événement de cette ligne:

self.$input.click().trigger('change');

Ne pouvait être que de tenter quelque chose? C'est peut-être lié à l'événement de clic plutôt que l'événement de changement? Essayez ceci vous reste-déclaration:

$(element).prop('checked', value).click().trigger('change'); // <--- this should work!

Ce que j'ai compris .cliquez sur la (les): Il simule un clic de souris, et dans le même temps, déclenche l'événement click (Euh?).

Je sais que parfois (comme pour une radio ou une case à cocher) certains codeurs sont contraignantes pour l'événement du clic, plutôt que de changer car c'est plus susceptibles de tirer au bon moment (dans IE7 le changement événement se déclenche vraiment dans une drôle de façon).

Juste une pensée, peut-être quelque chose à essayer. Espérons que cela aide!

EDIT: J'ai vu une réponse concernant les espaces de noms dans vos événements et des événements personnalisés. Cela pourrait aussi vous aider, j'espère que c'est pas un trop gros changement.

/J.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X