Хорошо, я уже несколько часов пытаюсь разгадать этот беспорядок и никуда не денусь, аналогично собаке, преследующей его хвост. Вот ситуация.
Я использую Knockout.js для своего пользовательского интерфейса, который отлично работает сам по себе. Тем не менее, я пытаюсь использовать сторонний код, который делает выпадающие списки и флажки выглядят красиво. На самом деле я даже не уверен, что это библиотека сторонних разработчиков или что-то, что написано нашими дизайнерами. Этот код скрывает реальный флажок и заменяет его поддельным <span />
, который имитирует флажок через CSS. Событие click
диапазона запускает событие change
реального флажка:
// 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);
Это действительно работает с Knockout.js, так как Knockout будет слушать этот обработчик событий. Другими словами, когда пользователь нажимает фальшивый флажок, обновляется связанная модель нокаута. Однако то, что не работает, - это обновление модели. Если я вызываю:
model.SomeValue(!curValue); // SomeValue is bound to a checkbox, flip its value
Модель обновляется, но поддельный пользовательский интерфейс не обновляется. Я проследил эту проблему до кода в ko.bindingHandlers.checked.update
, который выполняет следующие действия:
// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;
В принципе, свойство element.checked
установлено, но никаких событий не запускается. Таким образом, функция _changeEvent
никогда не вызывается. Итак, я реализовал свою собственную функцию ko.bindingHandlers.checked.update
, которая является копией встроенного. Теоретически это все, что мне нужно сделать:
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);
}
};
Вместо того, чтобы устанавливать element.checked
, я вместо этого вызываю .prop('checked', value)
и запускаю событие изменения. Однако это не работает. Вот что я знаю до сих пор:
- Если я удалю Knockout.js из уравнения,
$(element).prop('checked', value).trigger('change');
работает отлично. Итак, knockout.js прикручивает событие каким-то образом. Не отвязывает ли этот обработчик событий? - Я подтвердил, что
$(element)
- это то же самое, что иthis.$input
в фальшивом коде привязки кода. Я могу установить другие свойства expando на этот элемент, и они появятся. - Я пробовал несколько подходов, чтобы попытаться отладить в Knockout.js и jQuery, чтобы увидеть, все еще связано событие, однако я ничуть не с этим подходом. Моя догадка в том, что Knockout.js каким-то образом заменил обработчик события
change
своим собственным внутренним, и существующие привязки были удалены. Я еще не нашел способа подтвердить это.
Мой вопрос: В основном, я ищу решение этой проблемы. Does Knockout.js удаляет существующие события change
, которые были там до применения модели? Каковы следующие шаги по отладке этого кода и выяснению, что происходит?