Доброго времени суток, товарищи.
Столкнулся с одной проблемой в JQuery и теперь хочу выяснить: все как всегда (сам дурак и прощай остатки кармы) или все же это такая особенность JQuery?
Положим, есть следующий HTML-код:
<input id="dis" type="checkbox" />
<input id="chb" type="checkbox" /><input id="txt" type="text" />
* This source code was highlighted with Source Code Highlighter.
Схема работы предельно простая: чекбокс #chb управляет активностью текстового поля #txt (когда checked — !disabled и наоборот), а чекбокс #dis отключает (disabled=«disabled») чекбокс #chb и переключает его состояние.
Вот примерный код:
$("#chb").click(function() {
$("#txt").attr("disabled", ! this.checked);
});
$("#dis").click(function() {
if ( $("#chb").attr("checked") )
{
$("#chb").click();
}
$("#chb").attr("disabled", this.checked);
});
* 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) {
// отключаем стандартную обработку клика, сами справимся
e.preventDefault();
});
$("#dis").click(function() {
if ( $("#chb").attr("checked") )
{
$("#chb").mouseup();
}
$("#chb").attr("disabled", this.checked);
});
$("#chb").mouseup(function() {
// имитация клика — переключение
this.checked = ! this.checked;
$("#txt").attr("disabled", ! this.checked);
});
* 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. Но остается вопрос в причинах такого поведения.
_________
Текст подготовлен в
ХабраРедакторе
комментарии (11)
— The .triggerHandler() method does not cause the default behavior of an event to occur (such as a form submission).»
То есть, можно использовать тот же click(), дополняя имитацией стандартного поведения. Спасибо, попробую, возможно, так будет чуть проще.
я просто по клику делал setTimeout(handler, 0)
Помню что-то похоже меня удивило и причем оно по разному в IE и FF по порядку обрабатывалось.
Я в итоге добавлял на события change и keypress, а изначально пытался на click.
есть чекбокс и его родной онклик который меняет его состояние
есть навешаное тобой событие которое по клику меняет его еще раз
1 если ты реально кликаешь на чекбокас происходят оба события и состояние меняться два раза тоесть становиться снова тем которое было
2 если ты програмно вызыввешь триггер то происходят оба события с тем же результатом что и прошлый раз
3 если ты вызываешь тригер хендлер то происходит только то событие которое ты навесил через жуквери.
возможно тебе будет интересно как я воевал с этим в свое время
mabp.kiev.ua/2007/07/03/onmouseover_checkbox_toggler/