わかりました、私は数時間この混乱を解明しようとしてきましたが、犬が尻尾を追いかけているように、どこにも行き着きません. これが状況です。
私は自分の UI に 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 はそのイベント ハンドラーをリッスンするため、これは実際には Knockout.js で機能します。つまり、ユーザーが偽のチェックボックスをクリックすると、バインドされた Knockout モデルが更新されます。ただし、うまくいかないのはモデルの更新です。私が電話した場合:
model.SomeValue(!curValue); // SomeValue is bound to a checkbox, flip its value
モデルは更新されますが、偽の UI は更新されません。この問題を追跡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
のではなく、change イベントを呼び出し.prop('checked', value)
てトリガーします。ただし、これは機能していません。これが私がこれまでに知っていることです:
- 式から Knockout.js を削除すると、
$(element).prop('checked', value).trigger('change');
完全に正常に動作します。そのため、knockout.js は何らかの方法でイベントを台無しにしています。そのイベントハンドラーのバインドを解除していますか? - 偽のチェックボックス バインディング コード
$(element)
と同じであることを確認しました。this.$input
この要素に他の expando プロパティを設定すると、それらが表示されます。 - イベントがまだバインドされているかどうかを確認するために、Knockout.js と jQuery にデバッグしようとするいくつかのアプローチを試みましたが、このアプローチでは実際にはどこにも行きませんでした。私の推測では、Knockout.js がどうにかして
change
イベント ハンドラーを独自の内部ハンドラーに置き換え、既存のバインディングが削除されたということです。これを確認する方法はまだ見つかっていません。
私の質問:主に、この問題の解決策を探しています。Knockout.jschange
は、モデルが適用される前に存在していた既存のイベントを削除しますか? このコードをデバッグし、何が起こっているのかを正確に把握するための次のステップは何ですか?