Home > Software design >  Javascript validate checkboxes with array values
Javascript validate checkboxes with array values

Time:06-17

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 >Please select one option.</p>');
            errors[checkbox_groups[i]] = 'Field required';
            error = true;
        }
    }
    return !error;
}

HTML

<table >
    <thead>
        <tr>
            <th>Name</th>
            <th>X/th>
            <th>x</th>
            <th>x</th>
            <th>&emsp;</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[1]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[2]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[3]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[4]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
    </tbody>
</table>

CodePudding user response:

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 stripe 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 >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 >
    <thead>
        <tr>
            <th>Name</th>
            <th>X/<th>
            <th>x</th>
            <th>x</th>
            <th>&emsp;</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[1]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[2]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[3]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
        <tr>
            <td>
                <label >Test PErson
                <input name="person[4]" type="checkbox" data-required="1">
                <span ></span>
                </label>
            </td>
            <td>-</td>
            <td>Test</td>
            <td>Test</td>
            <td><a href="h#">Edit</a></td>
        </tr>
    </tbody>
</table>

  • Related