Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Чекбокс “Выбрать все” выбирает все чекбоксы, и наоборот

#javascript #html #jquery


При выборе главного checkbox'а выбираются все остальные, привязанные к нему, и наоборот,
при выборе всех привязанных выбирается и главный.

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

Поэтому сейчас реализовано так: у главного checkbox'а есть id, который совпадает
с классами зависимых checkbox'ов. Классы могут быть любые - главное что они совпадают
с id главного checkbox'а. 

Рабочий код можно посмотреть ниже, но он слишком массивный. Есть ли более элегантные
решения, желательно легко модифицируемые?



$(document).on("change", "input[type=checkbox]", function() { // По изменению checkbox'а
    if ($(this).attr('class')) {
        var CBgroupID = $(this).attr('class');
    }
    if (($(this).attr('id')) && ($('input[type="checkbox"].' + $(this).attr('id')).length)) { 
        var CBgroupID = $(this).attr('id');
        if (this.checked) {
            $('input[type="checkbox"].' + CBgroupID).attr('checked', 'checked');
            $('input[type="button"][class*="' + CBgroupID + '"]').removeAttr('disabled');
        } else {
            $('input[type="checkbox"].' + CBgroupID).removeAttr('checked');
            $('input[type="button"][class*="' + CBgroupID+'"]').attr('disabled',
'disabled');
        }
    }
    if (!CBgroupID) {
        return;
    }
    if ($('input[type="checkbox"].' + CBgroupID + ':not(:checked)').length) {
        $('input[type="checkbox"]#' + CBgroupID).removeAttr('checked');
    } else {
        $('input[type="checkbox"]#' + CBgroupID).attr('checked', 'checked');
    }
    if ($('input[type="checkbox"].' + CBgroupID+':checked').length) {
        $('input[type="button"][class*="' + CBgroupID + '"]').removeAttr('disabled');
    } else {
        $('input[type="button"][class*="' + CBgroupID + '"]').attr('disabled', 'disabled');
    }
    if ($('input[type="checkbox"].' + CBgroupID + ':checked').length === 1) {
        $('.jToEdit').removeAttr('disabled');
    } else {
        $('.jToEdit').attr('disabled', 'disabled');
    }
    delete CBgroupID;
});

Группа 1

Общий


Группа 2

Общий


Пример в fiddle.


Ответы

Ответ 1



$(document).on('change', 'input[type=checkbox]', function () { var $this = $(this), $chks = $(document.getElementsByName(this.name)), $all = $chks.filter(".chk-all"); if ($this.hasClass('chk-all')) { $chks.prop('checked', $this.prop('checked')); } else switch ($chks.filter(":checked").length) { case +$all.prop('checked'): $all.prop('checked', false).prop('indeterminate', false); break; case $chks.length - !!$this.prop('checked'): $all.prop('checked', true).prop('indeterminate', false); break; default: $all.prop('indeterminate', true); } });



Ответ 2



Можно: checkbox'ам в рамках одной группы присвоить уникальное значение data-атрибута (например, data-id). checkbox'ам, выбирающим все, дать один класс (например, .all), а остальным - другой (например, one). Тогда код может выглядеть следующим образом: JS: $(document).ready(function() { $(".all").on("change", function() { var groupId = $(this).data('id'); $('.one[data-id="' + groupId + '"]').prop("checked", this.checked); }); $(".one").on("change", function() { var groupId = $(this).data('id'); var allChecked = $('.one[data-id="' + groupId + '"]:not(:checked)').length == 0; $('.all[data-id="' + groupId + '"]').prop("checked", allChecked); }); }); HTML:

Группа 1

Общий


Группа 2

Общий


Полный пример в fiddle.

Ответ 3



Разбавлю ка я счастливый мирный уголок любителей jQuery суровым и прямолинейным vanilla JavaScript. Реализовывать будем так: засовываем группу checkbox'ов в обертку; на каждой обертке слушаем событие onchange; на каждое событие меняем количество отмеченных checkbox'ов, в зависимости от этого мы можем убрать/поставить "главный" checkbox если же нажали на "главный" checkbox, то выделяем или снимаем выделение со всех checkbox в обертке. Прилагаю свой пример, полная версия на jsFiddle: var count = item.getElementsByClassName('js-checkbox').length; var currentCount = 0; item.addEventListener('change', function(evt) { if (evt.target.classList.contains('js-checkbox-main')) { if (evt.target.checked) { setAllCheckboxes(item, true); currentCount = count; } else { setAllCheckboxes(item, false); currentCount = 0; } } else { evt.target.checked ? ++currentCount : --currentCount; console.log(currentCount) if (currentCount == count) { setAllCheckboxes(item, true); } else if (currentCount == count - 1){ if (!evt.target.checked) { item.getElementsByClassName('js-checkbox-main')[0].checked = false; } } } }, false); Операция getElementsByClassName(), особенно не от корня, очень быстрая, так что если количество checkbox будет динамически изменяться, их количество легко и незаметно для глаза можно пересчитывать на каждое сгенерированное событие. Код полностью независим от каких-либо библиотек. Уверен jQuery делает это примерно также (могу обманывать в этом утверждении, но как сделать это по другому просто не приходит в голову). Интересно было бы протестировать скорость работы обоих вариантов, но почему-то мне кажется, что разница может быть заметна только на очень большом количестве элементов, которые в пользовательском интерфейсе будут глупо достаточно выглядеть. Поэтому данный ответ имеет смысл только в том случае, когда в вашем проекте практически нет jQuery и Вы хотите от него уйти или никто его не знает в команде jQuery (странновато звучит), или в чисто академических целях.)

Комментариев нет:

Отправить комментарий