Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   При выборе чекбокса заносить его значение в массив (https://javascript.ru/forum/events/72595-pri-vybore-chekboksa-zanosit-ego-znachenie-v-massiv.html)

Batyabest 11.02.2018 15:00

При выборе чекбокса заносить его значение в массив
 
Добрый день. Есть такой код html:
<div id="qwestion_40" class="question_item">
	<b>Вопрос 2 (3 правильных варианта ответа - последовательность 5,2,3)</b>
		<div id="8" data-max="3" data-seq="1">
			<input name="qw_40[seq]" value="1" type="hidden">
			<input name="qw_40[cta]" value="3" type="hidden">
			<div><input id="answer_40_57" value="57" class="chbx" name="qw_40[]" type="checkbox">&nbsp;<label for="answer_40_57"><span></span>Ответ 1</label></div>
			<div><input id="answer_40_58" value="58" class="chbx" name="qw_40[]" type="checkbox">&nbsp;<label for="answer_40_58"><span></span>Ответ 2 (true)</label></div>
			<div><input id="answer_40_59" value="59" class="chbx" name="qw_40[]" type="checkbox">&nbsp;<label for="answer_40_59"><span></span>Ответ 3 (true)</label></div>
			<div><input id="answer_40_60" value="60" class="chbx" name="qw_40[]" type="checkbox">&nbsp;<label for="answer_40_60"><span></span>Ответ 4</label></div>
			<div><input id="answer_40_61" value="61" class="chbx" name="qw_40[]" type="checkbox">&nbsp;<label for="answer_40_61"><span></span>Ответ 5 (true)</label></div>
		</div>
</div>


Скажите, как мне при выборе чекбокса, заносить его значение в массив или например в скрытое поле input. Проблема в том, что мне нужно заносить последовательность выбранных чекбоксов. А значит, если пользователь передумал и какой-то чекбокс отменил, его значение должно удаляться из массива выбранных.
Пытался таким кодом, но он не удаляет убранный пользователем чекбокс из последовательности:
$(':checkbox').on('click', function() {
       var chbx = $(this);
       var seq = chbx.parent().parent().attr('data-seq');
             if (seq == 1) {
                if (chbx.is(':checked')){
                   console.log(chbx.val());
             }
       } 
});

laimas 11.02.2018 15:52

Цитата:

Сообщение от Batyabest
Проблема в том, что мне нужно заносить последовательность выбранных чекбоксов.

Это не проблема, просто нужно обрабатывать изменение каждого флажка, а в массив заносить всегда новые состояния всех выбранных флажков.

Batyabest 11.02.2018 15:52

Сейчас накропал такой код, вроде бы решает задачу, но хотел бы совета, может можно как-то улучшить?
var arr = [];
                        $(":checkbox").on('click', function() {
                            arr = $(":checkbox:checked").map(function(i,el){
                                return $(el).val();
                            }).get();
                            console.log(arr);
                        });

laimas 11.02.2018 15:53

Зачем набор выбранных флажков помещать в скрытое поле?

Batyabest 11.02.2018 15:54

laimas, подскажите, а как мне потом этот массив отправить на сервер - я планировал через скрытый input - тупеж да?))

Скажите, как исправить код с поста №3: он у меня значения всегда по порядку отправляет в массив, а мне нужно именно в том порядке, как клика пользователь

laimas 11.02.2018 15:57

Цитата:

Сообщение от Batyabest
подскажите, а как мне потом этот массив отправить на сервер

А на сервере и будет массив только выбранных флажков под ключом qw_40. Не выбранные флажки на сервер не передаются.

Цитата:

Сообщение от Batyabest
я планировал через скрытый input - тупеж да?

Еще какой. Не нужно дублировать имеющееся всякой ненужной хренью.

Batyabest 11.02.2018 15:59

Цитата:

Сообщение от laimas (Сообщение 477661)
А на сервере и будет массив только выбранных флажков под ключом qw_40. Не выбранные флажки на сервер не передаются.

Точно! Вот я лох чилийский...
Подскажите мне - у меня мой код отправляет значения по порядку в массив - то есть они всегда выстроены там в порядке возрастания значений. А мне нужно в том порядке, как кликал пользователь.

laimas 11.02.2018 16:11

Цитата:

Сообщение от Batyabest
Подскажите мне - у меня мой код отправляет значения по порядку в массив - то есть они всегда выстроены там в порядке возрастания значений. А мне нужно в том порядке, как кликал пользователь.

Ну если важен порядок набора, тогда флажки не должны иметь имен, чтобы на сервер их не отправлять, а выбор их через скрытое поле. Правда определять по значения кто есть кто, не самый лучший вариант.

Скорее правильнее будет именовать флажки по индексу в наборе

name="qw_40[1]"
name="qw_40[2]"
....

Скрытого поля не надо, а при выборе флажка помещать его вверх в форме, под последним выбранным. Если выбранный флажок сброшен, то он возвращается на свое место в форме - под полем чей индекс максимален но меньше чем у сброшенного.

В этом случае в массиве на сервере значения ключей, это есть последовательность выбора флажков.

Batyabest 11.02.2018 16:15

laimas,
Вот такой код собирает правильно последовательность. В итоге имею массив со значениями в выбранном порядке. Но проблема в том, что таких блоков у меня на странице может быть несколько - как мне для каждого формировать свой массив последовательности?

var checklist = [];

                            $(':checkbox').on('click', function() {
                                var val = this.value|0; // to int

                                if (this.checked) {
                                    checklist.push(val); // если в начало, то .ushift(val)
                                } else {
                                    var idx = $.inArray(val, checklist);
                                    if( idx > -1 ){
                                        checklist.splice(idx, 1);
                                    }
                                }

                                console.log(checklist);
                            });

laimas 11.02.2018 16:38

Batyabest,
а то что этот способ полная профанация, мысль не посещает? ;)

Надо полагать, что последовательность 5,2,3, это не прихоть, а номера вариантов ответов. А значит северу важно знать именно их. По уму, хотя я и не знаю что значат значения флажков, но сервер обязан знать, что 1, это 55, а 2, это 79. И ему от клиента эти значения не нужны, зная ключи этих значений он всегда сможет получить сами значения если надо.

Значит value флажков должны содержать значения ключей, а имена без индексов. Тогда значения массивов и будет порядком выбора.

Скрытым полем или как я предлагал, решайте сами. Но пользователю соблюсти последовательность и не видеть ее при этом (ведь варианты то он может менять) разве удобно? А вот если выбранные располагать согласно последовательности набора, это будет наглядно.

Batyabest 11.02.2018 21:37

laimas,
Все верно - в заголовке я просто указал для себя правильную последовательность ответов, на сервер же конечно должны приходить ID ответов, причем желательно в том порядке, что указано. А для этого мне нужно собрать массив для каждой такой группы чекбоксов, и отправить их на сервер, хоть строкой, хоть как, не принципиально. Поэтому и решил загнать их в скрытый инпут и отправить.
Проблема у меня в том, что код
var checked = [];
                            $(':checkbox').on('click', function() {
                              var chbx = $(this);
                              var seq = chbx.parent().parent().attr('data-seq');
                              var sel_list_seq = chbx.parent().parent().children('.sel_seq_list');
                              if (seq == 1) {
                                if (chbx.is(':checked')) {
                                  checked.push(chbx.val());
                                } else {
                                  var index = checked.indexOf(chbx.val());
                                  if (index != -1)
                                    checked[index] = null;
                                  checked = checked.filter(item => item != null);
                                }
                                sel_list_seq.val(checked);
                                console.log(JSON.stringify(checked));
                              }
                            });

делая все правильно со второго и последующих вопросов все варианты ответов загоняет в один массив checked, а нужно чтобы у каждого вопроса был свой массив.
Что я только не делал, чтобы решить вопрос, например собрал все вопросы, у которых дата атрибут data-seq=1 (то есть в этих вопросах важна последовательность ответа), потом собрал с них id и вот тут никак не получается создать массив с индексов по id вопроса, например checked['question_49']? checked['quesion_58']/ Или может есть другое изящное решение? Помогите мне пожалуйста.

laimas 11.02.2018 21:43

Если собирать, то должно быть так:

событие изменения флажка -> очищаем массив -> итерация всех флажков -> выбранный флажок в массив

А $.after/$.before просто бы перемещала флажки в поле, и сервер получил бы и что выбрали, и в каком порядке.

Batyabest 11.02.2018 21:50

laimas,
А как создать массивы для каждого из вопросов, где требуется последовательность? Чтобы потом в них заносить данные?

laimas 11.02.2018 21:56

Цитата:

Сообщение от Batyabest
А как создать массивы для каждого из вопросов

Зачем, если элементы формы и есть массив готовый, а правила должен задавать сервер.

Я не понимаю всех страданий и зачем они нужны. Масса id, к чему, зачем... Вы не усложняете решение? :)

laimas 11.02.2018 22:09

Видимо я понял суть - важно знать последовательность набора, а также важно, чтобы пользователь об этой последовательности не подозревал?

Batyabest 12.02.2018 09:39

Цитата:

Сообщение от laimas (Сообщение 477742)
Видимо я понял суть - важно знать последовательность набора, а также важно, чтобы пользователь об этой последовательности не подозревал?

Да, все верно.
Это тест, в котором у некоторых вопросов нужно не просто выбрать ответы, а выбрать их в правильном порядке. Естественно, пользователь подозревать не должен правильно он что-либо выбирает или нет.
Мой код собирает в массив, но в один, а мне нужно для каждого вопроса, где необходима последовательность собирать данные в свой массивчик, ведь таких вопросов на странице может быть несколько.
Помогите кодом пожалуйста, я уже весь измучился))
Потом на сервере эта последовательность сравнивается с правильной.

laimas 12.02.2018 10:36

Цитата:

Сообщение от Batyabest
Мой код собирает в массив, но в один, а мне нужно для каждого вопроса, где необходима последовательность собирать данные в свой массивчик, ведь таких вопросов на странице может быть несколько.

Да не проблема собрать и в несколько, вот только они вам не помогут узнать реалии, если их так собирать. Поправьте если я не прав.

Допусти есть набор: 1, 2, 3, 4. Правильный ответ в этом наборе будет 1, 2, 4, и с обязательным порядком 4, 2, 1.

Вы пакуете выбор пользователя в массив, а он выбирает так: 1 - 3 - 4, затем сбрасывает флажки 3, 1. В массиве первым будет 4. Даже если после этого он выберет флажки 2 и 1, массив на сервере 4, 2, 1 ведь не говорит о том в какой последовательности происходил набор. Это скорее "подбирали ответ и угадали".

Если уж и готовить эти массивы, то они должны хранить всю историю набора, чтобы можно было серверу знать реалии. То есть, сброс флажка не означает, что его выбор, ранее помещенный в массив, удаляется из массива. А в случае выбора 3 из 4, достаточно запомнить в этом массиве три первых выбора. Если сервер получит в массиве 2, 1, 4, а сам набор флажков будет верным - 4, 2, 1, то сравнение этих двух массивов покажет, что студент на сессиях марки пива изучал, а не предмет.

В противном случае вы получаете не последовательность, а порядок, и можете проверять только правильность порядка в наборе, но тогда и массива отдельного серверу не нужно.

Batyabest 12.02.2018 10:46

laimas,
да, ваша мысль верная касательно "подбирали ответ и угадали", но у нас важно на данный момент, чтобы они в принципе правильную комбинацию выбрали, а если мы будем давать возможность отправлять только 3 первых выбора, то это лишает их подумать, ошибиться и исправиться)) в конце концов - "подобрать ответ и угадать"))
Если углубиться в терминологию, то наверное да, нужен набор, в том порядке как расставил пользователь.

laimas 12.02.2018 10:56

Цитата:

Сообщение от Batyabest
у нас важно на данный момент, чтобы они в принципе правильную комбинацию выбрали

Ну тогда какой прок от дополнительных массивов? Почему не сделать так как я предлагал - выбранный флажок помещается вверх под последним выбранным (если такового нет, то первым). Сбрасываемый флажок помещается вниз (коли важно сделать правильный порядок, то порядок в форме сброшенных флажков не важен, серверу их все равно не получать).

Пусть как в примере значения флажков 1, 2, 3, 4. Если Порядок набора будет верен, то сервер получит массив:

qw_40 =>
0 => 4
1 => 2
2 => 1

Что будет свидетельствовать о том, что студент учил.

Batyabest 12.02.2018 11:04

Цитата:

Сообщение от laimas (Сообщение 477786)
Почему не сделать так как я предлагал - выбранный флажок помещается вверх под последним выбранным (если такового нет, то первым). Сбрасываемый флажок помещается вниз (коли важно сделать правильный порядок, то порядок в форме сброшенных флажков не важен, серверу их все равно не получать)

Здесь уже начинает играть фактор нашего директора, который просит, чтобы никуда ничего не перемещалось.
Поэтому я на данный момент нашел для себя только такое решение, но не могу сделать занесение в разные массивы. Код мой такой:

var checked = [];
                        
                        var item = $('.question_item').children('[data-seq="1"]');
                        
                        $(item).each(function() {
                            var quest_id = $(this).parent().attr('id');
                            checked.push(quest_id);      
                        });
                        
                            $(':checkbox').on('click', function() {
                              var chbx = $(this);
                              var seq = chbx.parent().parent().attr('data-seq');
                              var quest_id = chbx.parent().parent().parent().attr('id');
                              console.log(quest_id);
                              var sel_list_seq = chbx.parent().parent().children('.sel_seq_list');
                              if (seq == 1) {
                                if (chbx.is(':checked')) {
                                  checked.quest_id.push(chbx.val());
                                } else {
                                  var index = checked.indexOf(chbx.val());
                                  if (index != -1)
                                    checked[index] = null;
                                  checked = checked.filter(item => item != null);
                                }
                                sel_list_seq.val(checked);
                                console.log(JSON.stringify(checked));
                              }
                            });


То есть массивы я под каждый вопрос с последовательностью создаю, но потом почему-то в них ничего не заносится(((

laimas 12.02.2018 12:00

А отправка формы асинхронная или естественная?

Batyabest 12.02.2018 12:02

Цитата:

Сообщение от laimas (Сообщение 477797)
А отправка формы асинхронная или естественная?

По нажатию кнопки "Отправить" идет ajax отправка формы на обработчик, который делает проверку правильности ответов.

laimas 12.02.2018 12:40

Ну может все таки так?

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function() {
    $('input').change(function() {
        if(this.checked) $(this).closest('div').append('<input type=hidden name="'+$(this).data('group')+'[]" value='+this.value+'>');
        else $('[name^='+$(this).data('group')+'][value='+this.value+']').remove()
    })
    
    $('form').submit(function(e) {
        e.preventDefault();
        alert(JSON.stringify($(this).serializeArray()))
    })
});
</script>
</head>
<body>
<form autocomplete="off">
<div> Group 1
<label><input type="checkbox" data-group="a" value="1" /> A</label>
<label><input type="checkbox" data-group="a" value="2" /> B</label>
<label><input type="checkbox" data-group="a" value="3" /> C</label>
</div>
<div> Group 2
<label><input type="checkbox" data-group="b" value="1" /> A</label>
<label><input type="checkbox" data-group="b" value="2" /> B</label>
<label><input type="checkbox" data-group="b" value="3" /> C</label>
</div>
<input type="reset" />
<button>Send</button>
</form>
</body>
</html>

laimas 12.02.2018 13:16

Batyabest,
выполните на локальном сервере, по идее что и надо.

<?
if($_POST) {
    $a = [
        'a' => [1=>'A', 'B', 'C'],
        'b' => [1=>'D', 'E', 'F']
    ];

    exit(print_r(array_combine(array_keys($a), array_map(function($k, $v) use($a) {
        return array_replace(array_flip($v), array_intersect_key($a[$k], array_flip($v)));
    }, array_keys($_POST), $_POST)), 1));
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function() {
    $('input').change(function() {
        if(this.checked) $(this).closest('div').append('<input type=hidden name="'+$(this).data('group')+'[]" value='+this.value+'>');
        else $('[name^='+$(this).data('group')+'][value='+this.value+']').remove()
    });
    
    $('form').submit(function(e) {
        e.preventDefault();
        $.post(location, $(this).serializeArray(), function(d) {
            alert(d)
        })
    })
});
</script>
</head>
<body>
<form autocomplete="off">
<div> Group 1
<label><input type="checkbox" data-group="a" value="1" /> A</label>
<label><input type="checkbox" data-group="a" value="2" /> B</label>
<label><input type="checkbox" data-group="a" value="3" /> C</label>
</div>
<div> Group 2
<label><input type="checkbox" data-group="b" value="1" /> D</label>
<label><input type="checkbox" data-group="b" value="2" /> E</label>
<label><input type="checkbox" data-group="b" value="3" /> F</label>
</div>
<input type="reset" />
<button>Send</button>
</form>
</body>
</html>

Batyabest 12.02.2018 13:27

laimas,
О, да)) так работает.


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