Ant100
Ant100

Reputation: 403

How to remove value when a checkbox is unchecked?

I'm working on a search box which has three different fields which will be filled with ajax according to user's selection.

This is my html:

<div id="states">
    <input type="checkbox" name="states[]" value="01">
    <label for="states">State 01</label>
    <input type="checkbox" name="states[]" value="02">
    <label for="states">State 02</label>
    ...etc...
</div>

<div id="prov">
    <input type="checkbox" name="provs[]" value="01">
    <label for="states">Prov 01</label>
    <input type="checkbox" name="provs[]" value="02">
    <label for="states">Prov 02</label>
    ...etc...
</div>

<div id="cities">
    <input type="checkbox" name="cities[]" value="01">
    <label for="states">City 01</label>
    <input type="checkbox" name="cities[]" value="02">
    <label for="states">City 02</label>
    ...etc...
</div>

When you select the first set of checkboxes, the second one gets filled with all the provs acording to the states. So if State 1 has three provs, those provs show. If I also check State 2, then the provs for State 2 will append to the ones already showing from State 1.

Then the same thing for cities, it will show the respective cities to the checked provs.

I look at this question: On unchecking a checkbox trigger an event And did the following:

function(){
    var stateIds;
    var locUrl = $('#url');
    var $checks = jQuery('.dptoCheckbox').change(function () {
        stateIds= $checks.filter(':checked').map(function () {
            return this.value;
        }).get().join(',');
        console.log(stateIds);

        $.ajax({
            url: locUrl,
            async: false,
            type: "POST",
            data: "state_ids="+stateIds,
            dataType: "html",

            success: function(data) {
                $('#prov').html(data);          
            }
        });
    });

Then in my controller I retrieve the provs from DB by using the States ID.

So far it is working great, the only problem is, since I'm updating the ajax call everytime I check/uncheck a field. Consider this list:

If I check State 1 and State 2, then check Prov A and Prov C. Then I decide I no longer want State 2. If I uncheck State 2, a new ajax call is made and the provs list updates. Which causes first, Prov C to dissappear (this is correct behaviour) but also all the values checked from State 1 (Prov A) reset.

I was wondering if there is a way to update the provs lists (and later on the cities list) and only remove the provs from the uncheck State. Leaving all the other provs from other checked States as they were.

Thank you for reading this far, I hope I made my question clear, I wasn't sure how to explain it without writing my entire code (I tried to minimize it as much as possible).

Upvotes: 1

Views: 3621

Answers (2)

BonsaiOak
BonsaiOak

Reputation: 28941

Here's my guess, but I haven't tested it completely, and I'm not an expert javascript programmer either. Let me know if there are any errors. EDIT: here's a jsfiddle to demonstrate: http://jsfiddle.net/z590wdLo/3/

NOTE: This answer has been proven wrong. It's missing code to remove provinces that shouldn't be there. I'm not deleting it because it could be slightly modified to be useful.

First of all you're HTML is slightly messed up. One of the main goals of a label element is so that when the user clicks the label, it checks the box for them. The way your markup is written doesn't allow this. You need to change this:

<div id="prov">
    <input type="checkbox" name="provs[]" value="01">
    <label for="states">Province 01</label>
    <input type="checkbox" name="provs[]" value="02">
    <label for="states">Province 02</label>
    ...etc...
</div>

To this:

<div id="prov">
    <label>
        <input type="checkbox" name="provs[]" value="01"/>
        Province 01
    </label>
    <label>
        <input type="checkbox" name="provs[]" value="02"/>
        Province 02
    </label>
    ...etc...
</div>

I changed this on the #states div but you should change it on everything. Notice that I took away the for="states" attribute and also put the <input type="checkbox"... element inside the <label> element.

You also should have your server return results in JSON and change the data type of your request to match. You can do this in PHP with the json_encode() function. I'm not sure your JSON object will look like exactly, so you'll have to modify the code accordingly. I'm going to assume you have a numerical array of associative arrays which will each have items in them, provName and provID.

I'm also assuming that the value="01" in <input type="checkbox" name="provs[]" value="01"> is the provID and that Prov 01 in <label for="states">Prov 01</label> is the provName.

Also change this:

success: function(data) {
    $('#prov').html(data);          
}

To this:

success: function(data) {

    var province = [];
    var elements;

    //get the next element from the array and only continue if
    //there actually was something left to get
    while((province = data.pop) !== undefined) {

        //do not append the element if there already exists an element
        //is a descendent of div#prov,
        //is of the type input,
        //and has a value that matches the provinceID
        if($("div#prov input[value|='" + province.provID + "']") !== $()) {

            $('#prov').append('<label><input type="checkbox" name="provs[]" value="' + province.provID + '"/>' + province.provName + '</label>');

        }
    }
}

Good Luck.

Upvotes: 1

user1524745
user1524745

Reputation: 71

There is two ways to do this:

1) Control all the checked checkboxes in server side, and serve the checked content on every AJAX call

2) Deleting the child checkboxes without AJAX, you should add on every province a class with the state dependency, and on every city a class with the province dependency. I think this is the better way.

I will explain the second one with an example:

When the user check the state 01, a province 12 is added by AJAX call:

<input type="checkbox" name="provs[]" value="12" class="province_state_01">

When the user check the province 12, the city 23 is added:

<input type="checkbox" name="cities[]" value="23" class="city_province_12">

Now, if the user uncheck the province 01, we should delete the child cities, without AJAX call:

jQuery('#prov input').change(function () {
    if (!jQuery(this).is(':checked')) {
        province_unchecked = jQuery(this).val();
        jQuery('input.city_province_' + province_unchecked ).remove();
    } else {
        //Here you should add your AJAX call to add the cities
    }
});

Now, let's do the same for the states, we should iterate for cities:

jQuery('#states input').change(function () {
    if (!jQuery(this).is(':checked')) {
        state_unchecked = jQuery(this).val();
        jQuery('input.province_state_' + state_unchecked).each(function() {
            province_child = jQuery(this).val();
            jQuery('input.city_province_' + province_child ).remove();
            jQuery(this).remove();
        });
    } else {
        //Here you should add your AJAX call to add the provinces
    }
});

Upvotes: 1

Related Questions