0

Plot I have some dynamic js validations that first scan for all fields in a step (HTMLElement). Basically I populate checkbox_groups with all the names and then check if at least one is checked. This works good except a certain situation.

Problem I have some dynamic checkboxes that have names like: person[1], person[2], person[3]. Because the id is specified my error <p> appears under each checkbox instead of only the last checkboxes as intended. Basically all I want is to find a way to modify this script so in this scenario the error message to appear only after the last checkbox.

Code

/**
 * Validate step checkboxes
 *
 * @param {HTMLElement} element
 *
 * @returns {Object}
 */
function validate_step_checkboxes(step) {
    var checkbox_groups = [];
    var errors = [];
    var error = false;

    $.each(step.find('input[type="checkbox"][data-required="1"]'), function () {
        var myname = this.name;
        if ($.inArray(myname, checkbox_groups) < 0) {
            checkbox_groups.push(myname);
        }
    });

    console.log('groups');
    console.log(checkbox_groups);

    // Check if there is a checkbox selected for each checkbox group
    for (i = 0; i < checkbox_groups.length; i++) {
        if (step.find('input[type="checkbox"][data-required="1"]:checked').length <= 0) {
            $('input[type="checkbox"][data-required="1"][name="' + checkbox_groups[i] + '"]').last().closest('.checkbox-label').after('<p class="input-error">Please select one option.</p>');
            errors[checkbox_groups[i]] = 'Field required';
            error = true;
        }
    }
    return !error;
}

HTML

<table class="primary-table hidden-xs">
    <thead>
        <tr>
            <th>Name</th>
            <th>X/th>
            <th>x</th>
            <th>x</th>
            <th>&emsp;</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[1]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[2]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[3]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[4]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
    </tbody>
</table>
4
  • We really need to see a minimal chunk of your HTML; I've been playing around with your code but I'm having to guess (and work) to come up with what your HTML might look like. Can you add a minimal snippet that helps demonstrate the problem? Commented Jun 17, 2022 at 7:13
  • @Don'tPanic I added the table where this happens, basically I get the error message after every .checkbox-label intead of only the last one, because it sees all names as unique due to the [1], [2], [3], instead of detecting only person. Updated the post. Commented Jun 17, 2022 at 7:29
  • Well ... they are unique. Your HTML uses unique names, so they're all independent; but the JS assumes they're all part of a single set. Is there a reason you're using unique names? It is perfectly valid to group checkboxes in a set with the same name, eg person[] (or people[]). Commented Jun 17, 2022 at 7:42
  • Should I maybe simply use person[] and add their id's into the value attribute ? I will try it out and do some regression testing. Commented Jun 17, 2022 at 7:52

1 Answer 1

1

As described in the comments, the HTML defines each individual checkbox as part of a unique set (eg person[1]). But the Javascript expects those to be groups of checkboxes ...

There is nothing wrong with using a checkbox name like person, you can still have 10 checkboxes with that name and check as many or as few as you like. To make things easier on the backend it is common to use a name like person[], so you get an array of values. In this case since you're selecting multiple persons maybe people[] is an appropriate name.

If you really need unique names for each checkbox for some reason, the only way I can think of to get the JS to treat them as part of a single group is to strip off the [1] part to find the common "base" name. This does not seem like a good idea though, fragile and hacky. I've included a working example below, but I wouldn't recommend using this.

Maybe a better option would be to treat the block of HTML as the semantic group? So the input name isn't relevant, you're just looking for something checked inside that <div> (or maybe <table> in your case)? But again this doesn't feel like a good option, we're circumventing the built in properties that are supposed to do exactly this - the name specifies how inputs are grouped.

/**
 * Validate step checkboxes
 *
 * @param {HTMLElement} element
 *
 * @returns {Object}
 */
function validate_step_checkboxes(step) {
    var checkbox_groups = [];
    var errors = [];
    var error = false;

    $.each(step.find('input[type="checkbox"][data-required="1"]'), function () {
        var myname = this.name;
        
        // Check if this name includes [1], etc
        if (myname.match(/\[\d\]/)) {
            // It does, let's get the "base name" without [1]
            myname = myname.replace(/\[\d\]/, '');
            console.log('stripped', myname);
        } 
        if ($.inArray(myname, checkbox_groups) < 0) {
            checkbox_groups.push(myname);
        }
    });

    console.log('groups');
    console.dir(checkbox_groups);

    // Check if there is a checkbox selected for each checkbox group
    for (i = 0; i < checkbox_groups.length; i++) {
        if (step.find('input[type="checkbox"][data-required="1"]:checked').length <= 0) {
            $('input[type="checkbox"][data-required="1"][name^="' + checkbox_groups[i] + '"]').last().closest('.checkbox-label').after('<p class="input-error">Please select one option.</p>');
            errors[checkbox_groups[i]] = 'Field required';
            error = true;
        }
    }
    
    console.log('errors:');
    console.dir(errors);
    return !error;
}


$(document).ready(function() {
    let $step1 = $('.primary-table');
    let valid = validate_step_checkboxes($step1);
    console.log('valid:', valid);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="primary-table hidden-xs">
    <thead>
        <tr>
            <th>Name</th>
            <th>X/<th>
            <th>x</th>
            <th>x</th>
            <th>&emsp;</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[1]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[2]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[3]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label class="checkbox-label">Test PErson
                <input name="person[4]" type="checkbox" data-required="1">
                <span class="checkmark"></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
    </tbody>
</table>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.