首页 > 解决方案 > Disable button if checkboxes are unchecked - across groups - in an ajax response

问题描述

This is an adaptation of Disable button if all checkboxes are unchecked and enable it if at least one is checked

On the above post they are disabling a button unless at least 1 checkbox is checked.

In my situation, I have 2 sets of checkboxes:

<div class="clone-ctp__filters">
    <input type="checkbox"> <label>Foo 1</label>
    <input type="checkbox"> <label>Bar 2</label>
    <input type="checkbox"> <label>Baz 3</label>
</div>

<div class="clone-ctp__users">
    <input type="checkbox"> <label>Foo 5</label>
    <input type="checkbox"> <label>Bar 6</label>
    <input type="checkbox"> <label>Baz 7</label>
</div>

Followed by a submit button

<button>Continue</button>

What I'm trying to do is disable the 'Continue' button unless at least 1 checkbox is checked in both groups (.clone-ctp__filters and .clone-ctp__users).

The intention being that the 'Continue' button is only enabled when you have checked at least 1 filter (.clone-ctp__filters) and at least 1 user (.clone-ctp__users).

The checkboxes themselves have been rendered via an ajax response, i.e. the HTML is written to .clone-ctp__filters and .clone-ctp__users as the response from 2 separate ajax requests to get the appropriate data.

I've used ajaxStop to make sure the code to disable/enable the button fires after the ajax response has completed:

$(document).ajaxStop(function() {
    var checkBoxes = $('input[type="checkbox"]');
    checkBoxes.change(function () {
        $('button').prop('disabled', checkBoxes.filter(':checked').length < 1);
    });
    $('input[type="checkbox"]').change();
});

This has the same effect as the linked post. It will disable the button unless at least 1 checkbox is checked. But it has no bearing on which set of checkboxes that's from.

My solution to this was to duplicate the code, e.g.

var checkBoxes = $('.clone-ctp__filters input[type="checkbox"]');

Then when that completes repeat it with

var checkBoxes = $('.clone-ctp__users input[type="checkbox"]');

This goes against the principles of DRY. Is there a more elegant way to write this?

jquery 3.2.1

标签: javascriptjqueryhtmlajaxcheckbox

解决方案


for 循环(或 forEach)将是合适的。

此外,如果未选择任一组(我在下面使用) ,请确保禁用“提交” .some如果未选择最后一组,您当前的代码将禁用它。

var checkboxGroups = ['clone-ctp__filters', 'clone-ctp__users'].map(containerClass => $(`.${containerClass} input[type="checkbox"]`));
checkboxGroups.flat().forEach(checkbox =>
    checkbox.change(() =>
        $('button').prop('disabled', checkboxGroups.some(checkboxes => checkboxes.filter(':checked').length < 1))));
$('input[type="checkbox"]').change();

或者在香草 JS 中:

const $ = document.querySelector.bind(document);
const $$ = document.querySelectorAll.bind(document);

var checkboxGroups = ['clone-ctp__filters', 'clone-ctp__users']
    .map(containerClass => [...$$(`.${containerClass} input[type="checkbox"]`)]);
    
checkboxGroups.flat().forEach(checkbox =>
    checkbox.addEventListener('change', () =>
        $('button').disabled = checkboxGroups.some(checkboxes => checkboxes.every(checkbox => !checkbox.checked))));

$('button').disabled = true;
<div class="clone-ctp__filters">
    <input type="checkbox"> <label>Foo 1</label>
    <input type="checkbox"> <label>Bar 2</label>
    <input type="checkbox"> <label>Baz 3</label>
</div>

<div class="clone-ctp__users">
    <input type="checkbox"> <label>Foo 5</label>
    <input type="checkbox"> <label>Bar 6</label>
    <input type="checkbox"> <label>Baz 7</label>
</div>

<button>Continue</button>


推荐阅读