Доброго времени суток, товарищи.
Столкнулся с одной проблемой в JQuery и теперь хочу выяснить: все как всегда (сам дурак и прощай остатки кармы) или все же это такая особенность JQuery?
Положим, есть следующий HTML-код:
Схема работы предельно простая: чекбокс #chb управляет активностью текстового поля #txt (когда checked — !disabled и наоборот), а чекбокс #dis отключает (disabled=«disabled») чекбокс #chb и переключает его состояние.
Вот примерный код:
Казалось бы, ничего необычного?
Кликая по #chb, текстовое поле будет включаться/выключаться как и надо. А вот кликая по #dis, мы получим лишь отключение #chb. А как же #txt? Ведь выполнение $("#chb").click() должно гарантировать и его отключение тоже. (Если нет — поправьте меня, пожалуйста, и дайте ссылку на объясняющую статью. Спасибо.)
Как показал тест, существует некое несоответствие в последовательности действий.
При клике на чекбоксе мышью:
1) переключить checked;
2) выполнить повешенные на клик обработчики.
При программном вызове click():
1) выполнить повешенные на клик обработчики;
2) переключить checked.
(вы можете проверить, повесив на click alert)
То есть, одна и та же (казалось бы) операция вызывает разные последовательности действий.
Теперь понятно, почему не отключается #txt: в момент, когда выполняется обработчик (проверяющий, а не checked ли управляющий чекбокс?), чекбокс все еще checked.
Раз мы знаем, что происходит, значит можем решить проблему.
Все было бы просто замечательно, если бы где-то хранилось не только текущее состоянии элемента (checked), но и изменение состояния (+1 — checked изменился с false на true, -1 — c true на false). К сожалению, насколько мне известно, JQuery за этим не следит.
Немного матчасти для понимания дальнейшего. При клике на элемент последовательно генерируются три события:
1) mousedown
2) mouseup
3) click
За переключение состояния чекбокса отвечает именно click. А раз он ведет себя не так, как нам хочется, мы отключим его совсем и будем использовать mouseup.
Вот так мне видится решение:
Таким образом, из mouseup мы сделали click с предсказуемым поведением.
Прошу прощения за стиль изложения, читать трудно, но я не умею писать по-другому. Надеюсь, когда-нибудь кому-нибудь это пригодится.
А в комментариях буду рад объяснениям столь необычного явления, критике и более простым решениям (если они вообще требуются). Спасибо за внимание.
upd: Хабраюзер Yeah подсказал функцию triggerHandler, которая может вызывать обработчики, повешенные на события, без срабатывания стандартного поведения. Тогда можно сделать проще, изменив в начальном варианте пару строк:
И никаких mouseup. Но остается вопрос в причинах такого поведения.
Столкнулся с одной проблемой в JQuery и теперь хочу выяснить: все как всегда (сам дурак и прощай остатки кармы) или все же это такая особенность JQuery?
Положим, есть следующий HTML-код:
<input id="dis" type="checkbox" /><br><input id="chb" type="checkbox" /><input id="txt" type="text" /><br><br>* This source code was highlighted with Source Code Highlighter.
Схема работы предельно простая: чекбокс #chb управляет активностью текстового поля #txt (когда checked — !disabled и наоборот), а чекбокс #dis отключает (disabled=«disabled») чекбокс #chb и переключает его состояние.
Вот примерный код:
$("#chb").click(function() {<br> $("#txt").attr("disabled", ! this.checked);<br>});<br><br>$("#dis").click(function() {<br> if ( $("#chb").attr("checked") )<br> {<br> $("#chb").click();<br> }<br><br> $("#chb").attr("disabled", this.checked); <br>});<br><br>* This source code was highlighted with Source Code Highlighter.
Казалось бы, ничего необычного?
Кликая по #chb, текстовое поле будет включаться/выключаться как и надо. А вот кликая по #dis, мы получим лишь отключение #chb. А как же #txt? Ведь выполнение $("#chb").click() должно гарантировать и его отключение тоже. (Если нет — поправьте меня, пожалуйста, и дайте ссылку на объясняющую статью. Спасибо.)
Как показал тест, существует некое несоответствие в последовательности действий.
При клике на чекбоксе мышью:
1) переключить checked;
2) выполнить повешенные на клик обработчики.
При программном вызове click():
1) выполнить повешенные на клик обработчики;
2) переключить checked.
(вы можете проверить, повесив на click alert)
То есть, одна и та же (казалось бы) операция вызывает разные последовательности действий.
Теперь понятно, почему не отключается #txt: в момент, когда выполняется обработчик (проверяющий, а не checked ли управляющий чекбокс?), чекбокс все еще checked.
Так что же делать?
Раз мы знаем, что происходит, значит можем решить проблему.
Все было бы просто замечательно, если бы где-то хранилось не только текущее состоянии элемента (checked), но и изменение состояния (+1 — checked изменился с false на true, -1 — c true на false). К сожалению, насколько мне известно, JQuery за этим не следит.
Немного матчасти для понимания дальнейшего. При клике на элемент последовательно генерируются три события:
1) mousedown
2) mouseup
3) click
За переключение состояния чекбокса отвечает именно click. А раз он ведет себя не так, как нам хочется, мы отключим его совсем и будем использовать mouseup.
Вот так мне видится решение:
$("#chb").click(function(e) {<br> // отключаем стандартную обработку клика, сами справимся<br> e.preventDefault();<br>});<br><br>$("#dis").click(function() {<br> if ( $("#chb").attr("checked") )<br> {<br> $("#chb").mouseup();<br> }<br><br> $("#chb").attr("disabled", this.checked);<br>});<br><br>$("#chb").mouseup(function() { <br> // имитация клика — переключение<br> this.checked = ! this.checked; <br><br> $("#txt").attr("disabled", ! this.checked); <br>});<br><br>* This source code was highlighted with Source Code Highlighter.
Таким образом, из mouseup мы сделали click с предсказуемым поведением.
Прошу прощения за стиль изложения, читать трудно, но я не умею писать по-другому. Надеюсь, когда-нибудь кому-нибудь это пригодится.
А в комментариях буду рад объяснениям столь необычного явления, критике и более простым решениям (если они вообще требуются). Спасибо за внимание.
upd: Хабраюзер Yeah подсказал функцию triggerHandler, которая может вызывать обработчики, повешенные на события, без срабатывания стандартного поведения. Тогда можно сделать проще, изменив в начальном варианте пару строк:
$("#dis").click(function() {
if ( $("#chb").attr("checked") )
{
// сделаем поведение однообразным: сначала снимем галочку, а затем вызовем обработчики
$("#chb").attr("checked", false);
$("#chb").triggerHandler('click');
}
$("#chb").attr("disabled", this.checked);
});
* This source code was highlighted with Source Code Highlighter.
И никаких mouseup. Но остается вопрос в причинах такого поведения.