Невозможно запустить привязку данных Knockout с помощью jQuery

Пишу плагин с использованием jQuery и нокаута. У меня две радиокнопки. Я использую нокаут-привязку данных, чтобы проверять и снимать флажок с переключателя. Проблема в том, что когда я пытаюсь снять флажок с переключателя при нажатии другой кнопки с помощью jQuery, он не обновляет наблюдаемое свойство привязки.

<input  type="radio" data-bind="checked: selectedVal" name="1" value="fixedPrice"/>  Fixed Price
 <input class="hn" type="radio" data-bind="checked: selectedVal" name="1" value="allowBiding"/> Allow Biding
<pre data-bind="text:ko.toJSON($data,null,2)"></pre>
<input type="button" id="button" value="Click Me" />

 var onClick = function() {
   $('.hn').prop('checked', true);

};

$('#button').click(onClick);

var ViewModel = function () {
    var self = this;
    self.selectedVal = ko.observable("fixedPrice");
    self.selectedVal.subscribe(function (val) {
       console.log(val)
    });
};

ko.applyBindings(new ViewModel());

Пожалуйста, найдите этот jsfiddle ниже с более подробной информацией.


person Abhi Mukherjee    schedule 13.10.2015    source источник


Ответы (3)


jQuery и Knockout борются за контроль над представлением. Если вы собираетесь использовать модель просмотра, используйте модель просмотра и не управляйте DOM, кроме как через модель просмотра. У вас есть элемент viewmodel, который управляет переключателями, вам просто нужно его установить. Knockout предоставляет click привязку, поэтому вам не нужен jQuery для ее прикрепления.

var ViewModel = function () {
    var self = this;
    self.selectedVal = ko.observable("fixedPrice");
    self.selectedVal.subscribe(function (val) {
        console.log(val)
    });
    self.setSelected = function () {
        self.selectedVal('allowBiding');
    };
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="radio" data-bind="checked: selectedVal" name="1" value="fixedPrice" />Fixed Price
<input type="radio" data-bind="checked: selectedVal" name="1" value="allowBiding" />Allow Biding
<pre data-bind="text:ko.toJSON($data,null,2)"></pre>

<input type="button" value="Click Me" data-bind="click:setSelected" />

person Roy J    schedule 13.10.2015

Уэлп! Не смешивайте KO и jQuery таким образом. Вы сражаетесь с нокаутом, а не используете его. См. этот предыдущий ответ, который я написал для очень похожей ситуации и расширенного объяснения.

Обратите внимание, что это определенно не ошибка, jQuery по умолчанию не запускает события при таких изменениях DOM. Если вы настаиваете на смешивании KO и jQuery таким образом, обязательно сообщите об этом другим следующим образом:

ko.applyBindings({
  isChecked: ko.observable(false),  
  onClick: function() {
    $('.hn').prop('checked', true);
    $('.hn').trigger('click');
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

1. The radio button: <input type="radio" class="hn" data-bind="checked: isChecked">
<br>
2. Trigger it with jQuery: <button data-bind="click: onClick">trigger</button>
<hr>
Debug info:<br><textarea data-bind="text: ko.toJSON($root)"></textarea>

person Jeroen    schedule 13.10.2015
comment
@ Денди. Надеюсь, вы пытаетесь удовлетворить любопытство, а не планируете использовать. Это антипаттерн. - person Roy J; 13.10.2015
comment
@RoyJ, да, я знаю, Рой. просто из любопытства. - person Dandy; 13.10.2015
comment
Вызов click на переключателе уже изменяет его значение, поэтому вам не следует изменять значение checked, а затем вызывать click. - person Michael Best; 16.10.2015
comment
@MichaelBest Я думал, что вы правы, но когда я попытался удалить это, я заметил, что KO не видит фактического изменения. Я обновил свой ответ. Если вы измените мой фрагмент стека и удалите вызов prop, тогда Knockout не обновит модель представления на trigger. - person Jeroen; 16.10.2015

Похоже на ошибку. Однако вы можете попытаться вызвать собственный обработчик кликов, чтобы наблюдаемый объект обновился.

$('.hn').triggerHandler('click');

Or

$('.hn')[0].click();

Вот демонстрация JsFiddle

person Viktor Bahtev    schedule 13.10.2015
comment
Это не ошибка. Как вы заметили, Knockout реагирует на событие, а не на изменение свойства checked вручную с помощью JavaScript. - person Michael Best; 16.10.2015
comment
'$ ('. hn ') [0] .click ();' отлично работал у меня. Требовалось, чтобы он работал как часть автоматизированного инструмента визуального регрессионного тестирования, который я установил. Спасибо. - person Jamie Paterson; 09.01.2017