Knockout.Js ne détecte pas l’état de la case à cocher modifiée par programme

J’ai une simple case à cocher dont la valeur est ajustée par un peu d’infrastructure que j’écris pour conserver l’état persistant dans localStorage. Je suis conscient que cela serait normalement effectué en définissant le viewModel, mais l’infrastructure n’est pas au courant de l’existence de liaisons masquées et n’y a pas access.

Je ne pensais pas que cela poserait un problème, car je pensais que knockout se déroulait à partir de l’événement ‘change’. Toutefois, $checkbox.prop('checked', true).sortinggger('checked') ne peut pas déclencher mon observable. Même utiliser l’événement click directement ne me donne pas tout à fait ce dont j’ai besoin.

Quels sont les événements auxquels knock-out wire? Comment puis-je le faire lire l’état du contrôle?

Jsbin montrant ce comportement étrange ici . Essayez de sélectionner directement la case à cocher ou de cliquer sur le bouton.

J’ai trouvé un meilleur moyen de le faire. Il suffit de mettre ce code dans votre événement domready:

  $("input:checkbox").bind('change', function () { $(this).sortingggerHandler('click'); }); 

Les liaisons knock-out ne fonctionnent pas vraiment dans la façon dont vous pensez.

Découvrez: http://knockoutjs.com/documentation/custom-bindings.html

Voici une solution que vous pouvez utiliser, pas de jQuery, pas de liaison personnalisée.

Votre html restra le même.

 var m = { isChecked: ko.observable(false), infrastructureUpdatesCheckbox: function() { this.isChecked( this.isChecked() === true ? false : true); } }; ko.applyBindings(m); 

vous devez modifier le statut coché de la case à cocher via votre modèle de vue:

  var m = { isChecked: ko.observable(false) //,infrastructureUpdatesCheckbox: function() { //$chk = $(':checkbox'); //$chk // .prop('checked', !$chk.prop('checked')) // .sortinggger('change'); //this.isChecked(!this.isChecked()); // this - is your view model } }; 

voici la version mise à jour:

 function InfrastructureUpdatesCheckbox(){ var $cb = $(':checkbox'); var cb = $cb[0]; cb.checked = !cb.checked; // manually change checked status $cb.sortingggerHandler('click'); // run all event handlers bound to 'click' event } 

Je suppose que le problème concerne uniquement les cases à cocher (boutons radio). Les autres contrôles doivent se comporter correctement lorsque vous déclenchez des événements manuellement.

Vous avez probablement déjà trouvé une solution à votre problème, mais cela pourrait aider quelqu’un d’autre.

J’ai eu exactement le même problème. Ce que j’ai fait est d’utiliser un modèle pub-sub et que mon composant déclenche son propre événement de modification. Ce que vous pouvez ensuite faire, c’est que l’instance du composant d’infrastructure devant mettre à jour le modèle soit abonnée à cet événement, puis mettre à jour votre modèle. Mieux encore, votre modèle peut s’abonner à l’événement. Ainsi, votre modèle connaît le composant infrastructure plutôt que l’inverse.

Ainsi, votre composant d’infrastructure n’a pas besoin de connaître ko et vous pouvez le réutiliser n’importe où. Je suis certain que vous n’aurez d’autres utilisations que si vous prévoyez de réutiliser ce composant.

J’espère que cela vous aidera (désolé, il n’y a pas de code car je ne peux pas poster de code client sur SO, mais si quelqu’un veut un exemple, dites-le-moi et je ferai un jsfiddle pour l’illustrer.

Dans mon cas, cela s’est avéré être lié à un bogue jQuery. Je suis allé au github knockout issue tracker pour le retrouver; voir ici .

Finalement, j’ai fini par le faire dans mon composant:

 var isjQueryOld = /^(0|1)\.[0-8]\./.test($.fn.jquery); // <=1.8.* var toggleCheckbox = isjQueryOld ? jQueryOldToggleCheckbox : function($el) { $el.trigger('click') } //https://github.com/knockout/knockout/issues/987 function jQueryOldToggleCheckbox($el) { //This should be simple right? See http://stackoverflow.com/a/8595601/5056 //and "simulating events to adjust knockout models" jasmine spec //all this is nessessary to get everything working with knockout var changeTo = !$el.prop('checked'); if(changeTo) $el.attr('checked', true); else $el.removeAttr('checked'); $el.trigger('click'); $el.prop('checked', changeTo); } 

et dans mon code

  toggleCheckbox($el); 

Je ne sais pas quel événement knock-out écoute, vous pouvez probablement parcourir la source elle-même et la comprendre, mais une solution consisterait à utiliser une liaison personnalisée . Dans l’ init pour la liaison personnalisée, vous pouvez définir les gestionnaires que vous souhaitez pour tous les événements que vous souhaitez capturer (tels que changed ) et les utiliser pour forcer la liaison à exécuter la update à update .

Aujourd’hui, j’ai passé des heures à tomber dans la boucle du clic avec une approche check & click, à essayer ko.observable, à écrire en pureComputed ou même à infrastructureUpdatesCheckbox sans succès trop longtemps pour expliquer à ceux qui paient pour mon travail pourquoi je ne suis pas en mesure de vérifier bouton radio dans le maudit Knockout. Malheureusement, mon contexte (Magento 2 avec les plugins achetés) ne m’a pas permis d’implémenter un modèle de vue valide. Finalement, j’ai réussi à résoudre le problème avec un simple piratage afin d’append une deuxième entrée type = “radio” et de l’afficher au clic:

 selectRadioPayment: function (obj, event, method) { this.selectPaymentMethod(obj, event, method); $('.ko-payment-selector').show(); $('#p_method_' + method).hide(); $('#p_method_' + method).closest('.radio-payment-selector').show(); }, renderedPaymentMethods: function() { if(quote.paymentMethod) { var selectedMethod = quote.paymentMethod().method; $('#p_method_' + selectedMethod).hide(); $('#p_method_' + selectedMethod).closest('.radio-payment-selector').show(); } },   

J’espère que cela aidera quelqu’un un jour.