Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Вызов click() на radio не изменяет его checked (https://javascript.ru/forum/misc/54911-vyzov-click-na-radio-ne-izmenyaet-ego-checked.html)

demoniqus 06.04.2015 11:39

Вызов click() на radio не изменяет его checked
 
Добрый день!
Столкнулся с непонятной логикой поведения в FF.
На странице средствами javascript создается и настраивается форма. Сначала производится ее создание и настройка, а потом она append'ится в состав страницы.
В состав этой формы входит radio-группа. На каждый элемент группы через JQuery подвешен обработчик click(). В конце настройки формы, но до ее append'a на страницу, на первом radio принудительно вызывается его click().
В IE, Chrome, Safari все нормально. В FF проблема... обработчик по click вызывается нормально, а вот checked самого radio-элемента остается неизменным...
С checkbox'ами такая же картина... Замена click на change тоже эффекта не дало...
Что за ерунда? Мне что, писать собственную реализацию метода click?

laimas 06.04.2015 12:42

Можно погадать почему, но может все-таки код свой покажите?

ksa 06.04.2015 13:09

Цитата:

Сообщение от demoniqus
Что за ерунда?

Чую, что те инпуты находятся внутри label!

demoniqus 06.04.2015 13:12

(function(){
    var elemContainer = $('<div></div>');
    elemContainer.addClass('elem-container');
    formContainer.append(elemContainer);
    var image = $('<img class="grid-icon" src="styles/images/pivot/pivot-columns.png" />');
    elemContainer.append(image);
    var inputRadio = $('<input type="radio" class="elem-container-switcher" elemtype="cap" name="table-radio-group" id="table-radio-group-capElements" />');
    elemContainer.append(inputRadio);
    image.click(function(){inputRadio.click();});
    inputRadio.click(function(){
        if (this.checked) {
            elemContainer.parents('.table-headers-type-form:first').find('.active').removeClass('active');
            elemContainer.addClass('active');
        }
        console.log(this.checked)
    });
    elemContainer.append('<label for="table-radio-group-capElements" class="block-header">Заголовки</label>');
    var options = [
        //......
    ];
    var optionsList = $('<ul class="no-marked-list no-margin-list no-padding-list" id="options-list"></ul>');
    for (var i = 0; i < options.length; ++i) {
        //......
    }
    elemContainer.append(optionsList);
    elemContainer.append('<div class="selection-information"></div>');
    inputRadio.click();
    console.log(inputRadio.get(0).checked)
})();

click в предпоследней строчке кода


Первым делом я предположил, что что-то в составе страницы создает такую непонятку, но это оказалось не так.
Я написал вот так в чистой странице:
function(){
            var df = document.createDocumentFragment();
            var input = $('<input type="checkbox" id="checkbox1"></input>');
            input.click(function(){
                console.log('click => ' + (this.checked ? 'true' : 'false'))
            });
            input.change(function(){
                console.log('change => ' + (this.checked ? 'true' : 'false'))
            });
            input.click()
            $('#result').append(input);
        }

Во всех браузерах кроме FF input меняет свое состояние и в консоль пишется true. В FF при вызове input.click()в консоль пишется false и сам checkbox не меняет своего состояния.
Я сделал еще одну кнопку и повесил на нее функцию:
$('#do1').click(function(){
            var checkbox = $('#checkbox1');
            var df = document.createDocumentFragment();
            df.appendChild(checkbox.get(0));
            checkbox.click();
            $('#result').append(checkbox);
        });

Результат оказался таким, как я и предполагал: как только checkbox выпал из основного DOM-дерева, он перестал меняться. Использование вместо documentFragment обычного тега (document.createElement('div')) с таким же результатом подтвердило мои догадки.

И еще любопытный момент: физический click порождает также событие change, а программный click этого не делает. Это во всех браузерах.

demoniqus 06.04.2015 13:13

Цитата:

Сообщение от ksa (Сообщение 365145)
Чую, что те инпуты находятся внутри label!

Увы и ах, вынужден разочаровать - котлеты и мухи отдельно...

Кстати, ни разу так не пробовал... Любопытный эффект что ли? Или просто click зацикливается?

ksa 06.04.2015 13:19

demoniqus, ты нормальный хтмл пример в состоянии сделать? Или так на твой говнокод смотреть и дальше медитировать? :)

demoniqus 06.04.2015 13:21

Цитата:

Сообщение от ksa (Сообщение 365152)
demoniqus, ты нормальный хтмл пример в состоянии сделать? Или так на твой говнокод смотреть и дальше медитировать? :)

Выложить проект весом 700 метров?

demoniqus 06.04.2015 13:21

Вот модель происходящего
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" >
    
    $(function(){
        $('#do').click(function(){
            var df = document.createDocumentFragment();
            var input1 = $('<input type="checkbox" id="checkbox1"></input>');
            input1.click(function(){
                console.log('click => ' + (this.checked ? 'true' : 'false'))
            });
            input1.change(function(){
                console.log('change => ' + (this.checked ? 'true' : 'false'))
            });
            input1.click()
            $('#result').append(input1);
        });
    });
</script>
</head>
<body>
    <button id="do">CYCLE</button>
    <div id="result"></div>
    
</body>
</html>

ksa 06.04.2015 13:21

Цитата:

Сообщение от demoniqus
Выложить проект весом 700 метров?

Очередная дурь... :(

Ты понимаешь термин "тестовый пример"?

laimas 06.04.2015 13:23

Устанавливайте обработчик элементам при их добавлении на страницу, или делегируйте их обработку ближайшему родителю гарантировано присутствующему на странице.

ksa 06.04.2015 13:29

Цитата:

Сообщение от demoniqus
Вот модель происходящего

Уже хорошо. :yes:
Как вариант просто поменяй местами два последних действия. ;)

<!DOCTYPE html>
<html>
<head>
<script src='http://code.jquery.com/jquery-latest.js'></script>
<!--
<script src="https://code.angularjs.org/1.3.9/angular.min.js"></script>
<script src="https://code.angularjs.org/1.3.9/angular-route.js"></script>
<link rel='stylesheet type=text/css href=tmp.css' />
-->
<style type='text/css'>
</style>
<script type='text/javascript'>
$(function(){
	$('#do').click(function(){
		var df = document.createDocumentFragment();
		var input1 = $('<input type="checkbox" id="checkbox1" />');
		input1.click(function(){
			alert('click '+this.checked);
		});
		input1.change(function(){
			alert('change '+this.checked);
		});
		$('#result').append(input1);
		input1.click();
	});
});
</script>
</head>
<body>
<button id="do">CYCLE</button>
<div id="result"></div>
</body>
</html>

ksa 06.04.2015 13:31

Цитата:

Сообщение от demoniqus
Кстати, ни разу так не пробовал... Любопытный эффект что ли?

Там кагбэ двойной клик получается...

ksa 06.04.2015 13:33

Цитата:

Сообщение от demoniqus
Во всех браузерах кроме FF input меняет свое состояние и в консоль пишется true. В FF при вызове input.click()в консоль пишется false и сам checkbox не меняет своего состояния.

В моем примере в ФФ работает ...

demoniqus 06.04.2015 13:33

Цитата:

Сообщение от laimas (Сообщение 365159)
Устанавливайте обработчик элементам при их добавлении на страницу, или делегируйте их обработку ближайшему родителю гарантировано присутствующему на странице.

Форма сложная, ее компоненты связаны друг с другом через различные события. Я разделил ее создание и настройку на отдельные методы, чтобы можно было нормально понимать этот код. И очень не хотелось бы все это смешивать или вообще делать один ОЧЕЕЕЕЕЕЕЕЕЕЕЕЕЕНЬ длинный метод из-за одного только браузера...

ksa 06.04.2015 13:34

demoniqus, ты мой пример смотрел?
http://javascript.ru/forum/misc/5491...tml#post365164

laimas 06.04.2015 13:37

demoniqus, пофигу какая у вас там форма ибо вы явно прописываете добавление элементов, и при их добавлении нужно и устанавливать обработчик, а лучше делегировать родителю. А об иных проблемах, которые могут быть, написал ksa.

demoniqus 06.04.2015 13:40

Цитата:

Сообщение от ksa (Сообщение 365166)
В моем примере в ФФ работает ...

KSA, ты нарушил условие эксперимента.
Объясняю: я создаю некую форму (но еще не помещаю ее в дерево документа), навешиваю обработчики событий (которые влияют на состояние данной формы и содержат в себе определенную логику связей состояний элементов). Из-за логической связи состояний различных элементов формы их проще настроить, вызвав нужный обработчик, нежели писать еще кучу кода. Вот через тот самый click() я и вызываю эту настройку. И сделать это я хочу до того, как показать форму пользователю (самого как пользователя бесит жутко, когда у тебя на глазах начинают прыгать сами по себе разные прибамбасы по всей странице). И только потом уже готовую форму я append'ю в страницу. Ты же поменял настроечный click и append местами.

ksa 06.04.2015 13:44

Цитата:

Сообщение от demoniqus
ты нарушил условие эксперимента

Я только поправил твой тестовый пример... :cray:

ksa 06.04.2015 13:47

Цитата:

Сообщение от demoniqus
Из-за логической связи состояний различных элементов формы их проще настроить, вызвав нужный обработчик, нежели писать еще кучу кода. Вот через тот самый click() я и вызываю эту настройку. И сделать это я хочу до того, как показать форму пользователю

Ты сам себе создал проблемы и теперь застрял в особенностях того же ФФ. :) Т.ч. все как в анекдоте
Цитата:

- Доктор, когда я делаю так (сворачивается в немыслимую позу)... У меня сильно болит вот здесь.
- Не делайте так!

demoniqus 06.04.2015 13:50

Цитата:

Сообщение от ksa (Сообщение 365174)
Я только поправил твой тестовый пример... :cray:

Вот эта правка и изменила условие эксперимента.
Мне нужно, чтобы click происходил ДО ТОГО, как форма попадет в страницу. Особенно в свете особенностей работы того же IE, который примерно до 10х раз тормознутее того же Хрома и Лисы...
Сейчас на w3c читаю инфу по click и change и пока не вижу ничего такого, что могло бы объяснить подобное поведение в FF. Я просто хотел предположить, что в данном случае FF наиболее строго следует какой-нибудь спецификации (как это часто бывает в случае IE), но только не вижу такой спецификации.

Цитата:

Сообщение от ksa (Сообщение 365178)
Ты сам себе создал проблемы и теперь застрял в особенностях того же ФФ. :) Т.ч. все как в анекдоте

Это не портал анекдотов и не гороскоп. Это очень серьезное приложение, очень тяжелое. И оно было таким еще до меня. Приходится сравнительно долго ждать полной загрузки страницы прежде, чем все компоненты наконец займут свои места, что довольно сильно раздражает, т.к. невозможно быстро работать. Я стараюсь отдавать пользователю уже готовый интерфейс, который только нужно отрендерить без каких-либо дополнительных настроек.
И, как я сказал, это сложное приложение, а потому различные связи будут и никуда от этого не деться.
Вопрос в том, на что я наткнулся: это глюк Лисы или же это на самом деле нормальное поведение, а остальные браузеры просто прощают эту ошибку (сомневаюсь, что IE может быть лояльнее, чем хоть кто-нибудь другой)?

Цитата:

Сообщение от ksa (Сообщение 365178)
не делайте так

Если бы знать, где упадешь... кто ж знал, что click() может не изменить состояние checkbox и radio?

laimas 06.04.2015 13:56

>Мне нужно, чтобы click происходил ДО ТОГО, как форма попадет в страницу.

И каким это образом? Если нужно чтобы при добавлении группы, какой-то из ее элементов был установлен, например выбранный ранее пользователем, то этот выбор должен определять сервер. Делает это он не "щелчком", а посредством анализа запросов. Если заведомо известно какой должен быть установлен, по умолчанию например, то устанавливайте ему это свойство.

demoniqus 06.04.2015 14:20

Цитата:

Сообщение от laimas (Сообщение 365185)
>Мне нужно, чтобы click происходил ДО ТОГО, как форма попадет в страницу.

И каким это образом? Если нужно чтобы при добавлении группы, какой-то из ее элементов был установлен, например выбранный ранее пользователем, то этот выбор должен определять сервер. Делает это он не "щелчком", а посредством анализа запросов. Если заведомо известно какой должен быть установлен, по умолчанию например, то устанавливайте ему это свойство.

Сервер об этой radio-группе не знает и знать ему это вообще незачем. Я, наверное, ввел немного в заблуждение, использовав слово "форма". Речь идет не о теге FORM, а о простом фрагменте DOM-дерева. Подготовка и отправка данных идет через AJAX - в противном случае из-за циклических ссылок такие данные отправить нельзя. Эта radio-группа просто не может быть параметром. Она либо есть, если есть форма, либо их обеих вообще нет.
Чтобы максимально облегчить жизнь пользователю, сократить число телодвижений с его стороны, я по умолчанию выбираю первый элемент из radio-группы. Если бы от его состояния не зависели параметры иных компонентов, иные данные, то можно было просто тупо и надежно поставить input.checked = true. Но зависимость есть и потому я вызываю обработчик click(). И я никак не ожидал, что click() не изменит checked, да тем более только в одном браузере.


Часовой пояс GMT +3, время: 14:08.