We help IT Professionals succeed at work.

JavaScript Sort Ordering and Choice Limiting

maaknplan
maaknplan asked
on
139 Views
Last Modified: 2017-03-21
Hi

I have a simple form where the user can make up to three selections. The user can select the checkboxes in any order, but as they click on each one, the order in which they were checked is remembered, and the position is set to either 1, 2 or 3 when the checkbox is checked, or 0 if the checkbox is unchecked.

The catch is that if a user selects 3 checkboxes, but then unselects the checkbox in position 2, position 3 needs to become 2, so the order is 1,2 and not 1,3.

Example in w3schools

<!DOCTYPE html>
<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script>
        function IsChecked(chk) {

            if (TotalChecked() > 3) {
                alert('Only 3 boxes can be checked!');
                $(chk).prop("checked", false);
                return;
            }

            SetPosition();
        }

        function TotalChecked() {
            var total = 0;
            $(".chk").each(function () {
                if ($(this).prop("checked")) {
                    total++;
                }
            });

            return total;
        }

        function SetPosition() {
            var items = [];

            //Get the items and their values first
            $(".position").each(function () {
                var id = $(this).attr('id');
                var val = $(this).val();
                var item = { id: id, value: val };
                var chk = $("#" + id.replace("p", "c"));
                if ($(chk).prop("checked")) {
                    items.push(item);
                }
            });

            //Sort items

            items.sort(function (a, b) {
                return a.value - b.value;
            });

            $(".position").each(function () {
                var id = $(this).attr('id');
                var chk = $("#" + id.replace("p", "c"));
                var len = items.length;



                if ($(chk).prop("checked")) {
                    var val = $(this).val();

                    if (len == 0) {
                        if (val == 0) { val++ };
                    }
                    else if (len == 1) {
                        items[0].value = 1;
                    }
                    else if (len == 2) {
                        items[0].value = 2;
                        items[1].value = 1;
                    }
                    else {
                        items[0].value = 3;
                        items[1].value = 2;
                        items[2].value = 1;
                    }
                }
                else {
                    $(this).val(0);
                }
            });

            var i;
            for (i = 0; i < items.length; i++) {
                $("#" + items[i].id).val(items[i].value);
            }

        }
    </script>
</head>
<body>

    <input id="c1" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p1" class="form-control position" type="text" value="0" /><br />
    <input id="c2" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p2" class="form-control position" value="0" /><br />
    <input id="c3" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p3" class="form-control position" value="0" /><br />
    <input id="c4" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p4" class="form-control position" value="0" /><br />
    <hr />
    <p id="message"></p>
</body>
</html>

Open in new window


I just can't seem to get this to work, any help is much appreciated.

Thanks.
Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019
Commented:
This problem has been solved!
(Unlock this solution with a 7-day Free Trial)
UNLOCK SOLUTION
maaknplanSenior Developer

Author

Commented:
Thanks for the reply. Your solution is pretty elegant. The only issue is it doesn't reverse if you uncheck the checkboxes.

Here is what I ended up with - w3schools example.

<!DOCTYPE html>
<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script>
        function IsChecked(chk) {
            var total = TotalChecked();
            if (total > 3) {
                alert('Only 3 boxes can be checked!');
                $(chk).prop("checked", false);
                return;
            }
            var id = $(chk).attr('id');
            var pos = $("#" + id.replace("c", "p")); //Find the corresponding input
            var initVal = pos.val(); //Get the initial value of the corresponding input

            if ($(chk).prop("checked") == false) {
                pos.val(0); //Reset the corresponding input to 0 if the checkbox is unchecked
            }

            //If the corresponding input value of the function checkbox is 3, no changes need to be made as the other
            //inputs will be correctly set.
            if (initVal == 3) { return };

            switch (total) {
                case 1: //Only one checkbox is selected, so the corresponding input must be 1
                    if ($(chk).prop("checked") == true) {
                        pos.val(1); //If the function checkbox is checked, set the corresponding input to 1
                    }
                    else { //If the function checkbox is not checked, find the checked checkbox, and set its corresponding input to 1
                        $(".chk").each(function () {
                            if ($(this).prop("checked")) {
                                var id = $(this).attr('id');
                                var pos2 = $("#" + id.replace("c", "p"));
                                pos2.val(1);
                            }
                        });
                    }
                    break;
                case 2: //Two checkboxes are selected, so the corresponding inputs must be 1 and 2
                    if ($(chk).prop("checked") == true) {
                        pos.val(2); //If the function checkbox is checked, set the corresponding input to 2
                    }
                    else {//If the function checkbox is not checked, find the checked checkboxes, and set the corresponding inputs
                        $(".chk").each(function () {
                            if ($(this).prop("checked")) {
                                var id = $(this).attr('id');
                                var pos2 = $("#" + id.replace("c", "p")); //Find the corresponding input for the checked checkbox
                                //It doesn't matter if pos2.val() == 1
                                if (pos2.val() == 2) { 
                                    pos2.val(1);
                                }
                                else if (pos2.val() == 3) {
                                    pos2.val(2);
                                }
                            }
                        });
                    }
                    break;
                case 3:
                    if ($(chk).prop("checked") == true) {
                        pos.val(3);
                    }
                    break;
            }
        }

        function TotalChecked() {
            var total = 0;
            $(".chk").each(function () {
                if ($(this).prop("checked")) {
                    total++;
                }
            });
            return total;
        }

    </script>
</head>
<body>

    <input id="c1" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p1" class="form-control position" disabled="disabled" type="text" value="0" /><br />
    <input id="c2" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p2" class="form-control position" disabled="disabled" value="0" /><br />
    <input id="c3" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p3" class="form-control position" disabled="disabled" value="0" /><br />
    <input id="c4" onchange="IsChecked(this)" class="chk" type="checkbox" />
    <input id="p4" class="form-control position" disabled="disabled" value="0" /><br />
    <hr />
    <p id="message"></p>
</body>
</html>

Open in new window

maaknplanSenior Developer

Author

Commented:
The solution offered is simple and elegant, however it does not allow the order selected to be reversed.
CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019

Commented:
however it does not allow the order selected to be reversed.

Please explain by reversed?
CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019

Commented:
Just to explain the solution a bit more.

The paradigm of this solution is to use a progressive counter - like the queue tickets you sometimes get in a store. Each click represents a new arrival and so gets the next number in the queue. A click off represents the leaving of the queue so the number goes down to 0.

The checkbox with the lowest (non-zero) value is the one that was clicked first out of all the remaining clicked items.

The actual value in this case is not relevant - only its magnitude relative to the values of the other clicked items - which provides an ordering on the selected checkboxes.

Trying to see how this solution does not meet the requirements of the questions asked?

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions