Disabled button SEND

I try to make attribute disabled="" when checkbox is marked for the GDPR consent.
How to include inside input area disabled=" " if two check boxes are not marked?

In this case CSS properties will be set for cursor ‘not-allowed’ as it is disabled=" " inside input attributes.

Need help.

I’m not sure if I’m understanding your question, but in Javascript to disable an element you need to set the disabled attribute to true or false.

1 Like

Do you mind providing any code that you might have in this matter? If I understand it correctly, you want to keep a button disabled until two checkboxes are checked. If that’s the case, you need to bind the change event in those checkboxes, detect if both of them are checked, and add or remove the disabled attribute from your button accordingly. Something like this

const checkboxes = document.querySelectorAll('input[type="checkbox"]'); //Grab all checkboxes
const button = document.querySelector('input[type="button"]'); //Grab button

// Detect if checkboxes are checked.
// If they removed the disabled attribute
// Otherwise, add the disabled attribute

function handleCheckboxChange (checkbox) {
  if (checkboxes[0].checked &&
     checkboxes[1].checked) {
    button.removeAttribute('disabled');
    return;
  }
  button.disabled = true;
}

// Keep watching for changes in the checkboxes.
checkboxes.forEach(el => {
  el.addEventListener('change', handleCheckboxChange);
});

This is one approach – if you want to use it, you have to adapt it to your match your markup. Make sure you add the attribute by default in your button tag. I created a pen so you can visualize it.

Yes this is what I try to manage.
Thank you for the information. Need to test.

I have modified but still a syntax error.

checkboxes.forEach(el =>
 {
  el.addEventListener('change', handleCheckboxChange);
 }
);

You have used backticks rather than quotes.

As there’s trouble happening here, I’m going to use the following example radio buttons which must be checked along with the GDPR checkbox before the submit button is enabled.

Sample HTML code

Here is some sample HTML code for which we require that one of the options and the GDPR checkbox are both checked.

<form method="post" action="assign_gender.php">
    <fieldset>
        <legend>Gender identity</legend>
        <p><input type="radio" name="gender" id="cisgender"> <label for="cisgender">Cisgender (matches sex)</label></p>
        <p><input type="radio" name="gender" id="lesbian"> <label for="lesbian">Lesbian</label></p>
        <p><input type="radio" name="gender" id="gay"> <label for="gay">Gay</label></p>
        <p><input type="radio" name="gender" id="bisexual"> <label for="bisexual">Bisexual</label></p>
        <p><input type="radio" name="gender" id="transgender"> <label for="transgender">Transgender</label></p>
        <p><input type="radio" name="gender" id="transsexual"> <label for="transsexual">Transsexual</label></p>
        <p><input type="radio" name="gender" id="queer"> <label for="queer">Queer</label></p>
        <p><input type="radio" name="gender" id="questioning"> <label for="questioning">Questioning</label></p>
        <p><input type="radio" name="gender" id="intersex"> <label for="intersex">Intersex</label></p>
        <p><input type="radio" name="gender" id="asexual"> <label for="asexual">Asexual</label></p>
        <p><input type="radio" name="gender" id="ally"> <label for="ally">Ally</label></p>
        <p><input type="radio" name="gender" id="pansexual"> <label for="pansexual">Pansexual</label></p>
    </fieldset>
    <p><input type="checkbox" name="gdpr_consent" id="gdpr_consent"> <label for="gdpr_consent">GDPR consent?</label></p>
    <p><input type="submit" value="Submit" disabled></p>
</form>

Initial JS code

Here is the working code that has been slightly modified to work both with checkboxes and options. It ensures that a radio selection and the GDPR checkbox are checked before the form can be submitted.

const radios = document.querySelectorAll('input[type="radio"]');
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const button = document.querySelector('input[type="submit"]');

function countChecked(elements) {
    return elements.filter(element => element.checked).length;
}
function handleInputChange(checkbox) {
    button.setAttribute("disabled", "");
    if (countChecked(radios) + countChecked(checkboxes) >= 2) {
        button.removeAttribute('disabled');
    }
}

radios.forEach(el => el.addEventListener('change', handleInputChange));
checkboxes.forEach(el => el.addEventListener('change', handleInputChange));

Checking the form on page load

Instead of setting the HTML element to be disabled, we can instead trigger the change event on one of the elements. That way on page load the code checks and finds we don’t have enough checked elements, and disables the submit button.

function triggerEvent(element, eventType) {
    element.dispatchEvent(new Event(eventType));
}
...
triggerEvent(checkboxes[0], "change");

The disabled attribute is no longer needed on the submit button.

<!--<p><input type="submit" value="Submit" disabled></p>-->
    <p><input type="submit" value="Submit"></p>

This lets the form be more accessible, so that it still works when JS isn’t active too.

Investigating the count check

The magic line that does the check is as follows:

    if (countChecked(radios) + countChecked(checkboxes) >= 2) {

I don’t like how we are checking that the count matches a certain number. That results in too much fragility when things need to change.

There are certain things that can be done to better organize this check.

A list of named elements

Instead of checking for a certain number, it is better to have a list of named elements that we care about. That way we can check if there are the same number of named and checked elements.

Here is the list of names for the named elements:

// const radios = document.querySelectorAll('input[type="radio"]');
// const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const names = ["gender", "gdpr_consent"];
const button = document.querySelector('input[type="submit"]');

The handleInputChange function can then call countChecked with elements retrieved from those names.

function handleInputChange(field) {
    const elements = getElementsByNames(names);
    button.setAttribute("disabled", "");
    if (countChecked(elements) === names.length) {
        button.removeAttribute('disabled');
    }
}

We just need a getElementsByNames function to turn those names into matching elements:

function getElementsByNames(names) {
    const getElements = selector => Array.from(document.querySelectorAll(selector));
    return names.flatMap(name => getElements(`[name="${name}"]`));
}

I’m using a separate getElements function here to help us change the nodeList from querySelectorAll into an Array list. That way flatMap can easily turn the multiple arrays into a single array of elements instead.

Replacing checkboxes with named elements

The rest of the code that deals with checkboxes can be updated to use namedElements instead.

const namedElements = getElementsByNames(names);
// radios.forEach(el => el.addEventListener('change', handleInputChange));
// checkboxes.forEach(el => el.addEventListener('change', handleInputChange));
namedElements.forEach(el => el.addEventListener('change', handleInputChange));
// triggerEvent(checkboxes[0], "change");
triggerEvent(namedElements[0], "change");

Summary

Now, it is only the following two lines at the top of the code that are responsible for most of the configuration.

const names = ["gender", "gdpr_consent"];
const button = document.querySelector('input[type="submit"]');

and no matter how many named elements that we care about, the code ensures that all of the names must have a checked element.

Here is the full JS code:

const names = ["gender", "gdpr_consent"];
const button = document.querySelector('input[type="submit"]');

function getElementsByNames(names) {
    const getElements = selector => Array.from(document.querySelectorAll(selector));
    return names.flatMap(name => getElements(`[name="${name}"]`));
}

function countChecked(elements) {
    return elements.filter(element => element.checked).length;
}

function handleInputChange(field) {
    const elements = getElementsByNames(names);
    button.setAttribute("disabled", "");
    if (countChecked(elements) === names.length) {
        button.removeAttribute('disabled');
    }
}

function triggerEvent(element, eventType) {
    element.dispatchEvent(new Event(eventType));
}

const namedElements = getElementsByNames(names);
namedElements.forEach(el => el.addEventListener('change', handleInputChange));
triggerEvent(namedElements[0], "change");

The full code with the above improvements is found at https://jsfiddle.net/u7j1hd36/2/

There’s only one thing extra needed and that’s a disabled message stating what needs to be done, for which some separate validation might be put to good use.

2 Likes

Thank you for the message.