Prachi Agarwal
Prachi Agarwal

Reputation: 79

Multiple Conditions to a checkbox

I have a table named, student_db which is like this :-

Name    Gender  Grade   City
John    Male    2   North
Dave    Male    4   North
Garry   Male    3   North
Chirsty Female  5   East
Monica  Female  4   East
Andrew  Male    3   East
Patrick Male    7   South
Maria   Female  3   South

I need to select 3 students with this list, names of the students are taken as input. But there are some constraints :

1) 1 Female has to be selected.

2) A maximum of 2 persons from the same city can be selected.

3) Sum of the grade of the selected 3 persons cannot exceed 11.

4) Once three valid selections are made, rest of the checkboxes should freeze automatically.

5) If while selecting a person any of the constraint gets violated, that particular selections gets unchecked and a alert message is displayed to the user.

Is it possible to add so many constraints to a check box ??


EDIT

I have managed to add 2 constraints :-

1) If the grade sum exceeds 11, an alert message will get displayed.

2) Once three valid selections are made, rest checkboxes will get freezed.

This is what I've tried :-

<script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript"></script>
<script type="text/javascript">
    jQuery(function() {
        var max = 3;
        var checkboxes = $('input[type="checkbox"]');

        checkboxes.change(function() {
            var current = checkboxes.filter(':checked').length;
            checkboxes.filter(':not(:checked)').prop('disabled', current >= max);
        });
    });
</script>

<script>
    function jsFunction(element) {
        var sum = 0,i;
        var elements = document.getElementsByClassName('chkbox');

        for (i = 0; i<elements.length; i++) {
            if (elements[i].checked) {
                sum += parseInt(elements[i].value);
            }
        }

        if (sum > 11) {
            alert("11 maximum grade allowed !!");
            element.checked = false;
        }
    }
</script>

<form name='checkbox1[]' method="post" action="select_student.php">       
    <label class="cb1" for="checkbox1"> </label>
    <input type="hidden" name="checkbox1[]" id="check" value="null">

    <?php
        session_start();
        mysql_connect("localhost", "my_db", "my_password") or die (mysql_error ());
        mysql_select_db("my_db") or die(mysql_error());
        $strSQL = "SELECT Name,Grade FROM student_db";
        $rs = mysql_query($strSQL);
        echo "<b><h2>List of Students :-</h2></b>";

        while($row = mysql_fetch_array($rs)) {
            $man = $row['Name'];
            echo '<input type="checkbox" value="'.$row['Name'].'|'.$row['Grade'].'" class="chkbox"  name="checkbox1[]" onchange="jsFunction(this)" />';
            echo $man;
        }
    ?>
    <br>

    <input type="submit" value="SUBMIT" id="button1" style= "height:40px; width:150px; font-weight: bold; font-size:10;">
</form>

The JS function is used to check whether the Grade sum is exceeding 11 or not and the jQuery Functions freezes other boxes once 3 valid selections are made. But I am unable to add other constraints.

Upvotes: 1

Views: 2855

Answers (1)

talemyn
talemyn

Reputation: 7960

Sorry for the delayed response! I got caught up in some other stuff yesterday and had to pick back up this morning . . . hopefully, this will help you out.

What you have is a pretty good start . . . here's a few changes that I would suggest:

1) First off, some HTML changes:

  • store off all of your student data (i.e., the "gender", "grade", and "city" values) as data attributes in the checkbox, like this:

    <input type="checkbox" value="NAME_VALUE" class="chkbox" name="checkbox1[]"
           data-gender="GENDER_VALUE" data-grade="GRADE_VALUE" data-city="CITY_VALUE"
           onchange="jsFunction(this)" />
    
  • next, since you are already using jQuery, for clarity and easy of maintenance in the future, apply the onchange event listener dynamically, rather than hardcoding it into the input, like this:

    <input type="checkbox" value="NAME_VALUE" class="chkbox" name="checkbox1[]"
           data-gender="GENDER_VALUE" data-grade="GRADE_VALUE" data-city="CITY_VALUE" />
    

    . . . and, in the script, after the page load:

    $(".chkbox").on("change", jsFunction);
    
  • And, finally (just as a heads up), if you intend to us a <label> tag with a for attribute (e.g., you are showing one for your "hidden" input), you will need a matching id attribute in yout <input>, in order for them to be paired.

2) As for your scripting, I threw together the following that accomplishes all of the validation checks that you were looking for and standardizes some of your coding (you had a heavily mixed use of jQuery and vanilla JS).

var MAX_CHECKED = 3;
var MAX_GRADE = 11;

$("document").ready(function() {
    $(".chkbox").on("change", jsFunction);
});

function jsFunction() {
    var sum = 0;
    var cities = [];

    var elements = $(".chkbox");
    var checkedElements = elements.filter(":checked");

    checkedElements.each(function() {
        sum += parseInt($(this).data("grade"), 10);
        cities.push($(this).data("city"));
    });

    var uniqueCities = cities.filter(function(currentCity, cityIndex, cityArray) {
        return (cityIndex === cityArray.indexOf(currentCity));
    });

    if (sum > MAX_GRADE ) {
        alert(MAX_GRADE + " maximum grade allowed!!");
        $(this).prop("checked", false);
    }
    else if (uniqueCities.length !== cities.length) {
        alert("You may not select more than one student from each city!!");
        $(this).prop("checked", false);
    }
    else {
        if (checkedElements.length >= MAX_CHECKED) {
            if (checkedElements.filter("[data-gender='Female']").length < 1) {
                alert("At least one female student must be selected!!");
                $(this).prop("checked", false);
            }
            else {
                elements.filter(':not(:checked)').prop('disabled', true);
            }
        }
        else {
            elements.filter(':not(:checked)').prop('disabled', false);
        }
    }
}

Most of the code should be pretty straightforward . . . let me touch on a couple of the key or more complex parts . . .

  • Globals - I set your global variables (MAX_CHECKED and MAX_GRADE) up at the top and outside of any functions, so that they are accessible anywhere and easy to update (i.e., you don't have to search through the code to find them).
  • "Setup code" - I moved your setup code from the jQuery(function() { that you used to $("document").ready(function() { simply for readablity. :) They do the same thing.
  • Event binding the checkboxes - as I mentioned, I did this dynamically rather than inline, using $(".chkbox").on("change", jsFunction);. Additionally, you'll notice that I changed the selector. Since each checkbox is tagged with the "chkbox" class, I selected based on that, it is significantly faster than $('input[type="checkbox"]')
  • The validation logic - basically, you want to catch invalid entries as soon as possible and you have rules that fall into two categories: rules that can be checked before the maximum number of selections have been met and rules that require the maximum. The "max grade" and "unique cities" checks should be caught as soon as they are hit, but you must wait until you've hit the maximum selections before you can check for gender, since the user can always check a female student later on, if they have not yet hit the max.
  • uniqueCities - the function used to create this value isn't quite as straighforward as the rest of the code, so I'll clarify it a little. It is using the .filter method that is native to Arrays, to trim down the selections to only unique values. It does this by doing a callback which checks to see if the index of the current item (i.e., cityIndex) is the same as the index of the first instance of that value (i.e., currentCity) in the array (i.e., cityArray). If it is, then that value is added to the "filtered" array (i.e., uniqueCities).
  • "undisabling" - I added in an else statement that re-enables the checkboxes if the maximum number of selections have been made, but then one of them is unchecked. This will allow the user to change their mind, even if they had already hit the max, at some point.

A couple of extra notes

1) You need to change the value of Patrick's to "6" at the most, in order to check that the "at least one female" logic is working . . . currently, the lowest combination of all male students, from unique cities, is John, Garry, and Patrick, but their grade total is 12, so it triggers the "grade sum is too high" validation first. :)

2) While I didn't cover the code for this, you need to develop a version of this validation logic for your "Submit" button as well. If you don't, then someone could select two boys and hit "Submit" and the "at least one female" logic would never be triggered.

One way would be to put the "at least one female" validation in its own method and calling both from the "I just clicked on a checkbox" validation and in a "I just clicked on the submit button" validation. The main difference would be that, for the submit, you would not check to see if the max number of selections had been made, before triggering the "female" check. That would also be a good place to add an "at least one selection has been made" validation, as well.

Upvotes: 1

Related Questions