1

I have a set of dynamically built checkboxes (sub-categories of main-category).

<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001700">first</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001800">second</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001900">third</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18002000">forth</input>

Now when I submit the form, when I return back to the form from Server (if didn't pass validation, for example) I would like to be able to reconstruct that list of checkboxes with their values. Assume that the first two checkboxes were checked by the user I would like to have something like this:

<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001700" checked>first</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001800" checked>second</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18001900">third</input>
<input type="checkbox" name="SubCats" class="subcat-checkbox" value="18002000">forth</input>

I assume that I do that as one of the first things here:

(document).ready(function () {

    loadSubCategories();
}

I am using ASP.NET MVC and I can't figure out how do I deliver that information into the View (the HTML). I assume this is a common task in web development. How is it done in general?

dsb
  • 2,347
  • 5
  • 26
  • 43
  • Are you creating the checkboxes dynamically per JavaScript or in the view? – Greg Jul 30 '15 at 12:07
  • You should be using a view model which would contain a property for the value (I'm assuming they should all be different and not all `"18001700"` as you have shown), a property for the associated display text and a boolean property to bind a checkbox to. The view would have `@model List` and then generate the controls using strongly typed html helpers in a `for` loop so the controls are correctly named with indexers and you get 2-way model binding. –  Jul 30 '15 at 12:08
  • [This answer](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) gives you some options for dynamically creating new items in the collection. –  Jul 30 '15 at 12:10
  • @Greg, and others, I am building these checkboxes via javascript. So I assume that ViewModel will not help me here, I need to have html hidden fields for that, right? – dsb Jul 30 '15 at 12:34
  • @dsb, The view model will help you (and this would be almost impossible without it). In particular unchecked checkboxes do not post back a value, so if you generate 10 new checkboxes with duplicate names (not indexed) and only check 2, then currently all your controller can access is `int[] SubCats` which will contain only 2 values. Therefore if you return the view, only 2 those 2 checkboxes could ever be generated. –  Jul 30 '15 at 12:42
  • Which is why you need a model to bind to and inside a `for` loop you have `@Html.HiddenFor(m => m.SubCategories[i].ID)` and `@Html.CheckBoxFor(m => m.SubCategories[i].IsSelected)` etc - your posting back all ID's and an associated boolean value indicating if its been selected –  Jul 30 '15 at 12:44
  • You need some way to identify the individual checkboxes, e.g. id or custom data-* attributes. If you post the data with AJAX you can save the current state in a javascript variable or as Ahs n suggests local storage. If you are aiming for a single page application take a look at AngularJS or similar frameworks. – Greg Jul 30 '15 at 13:11

2 Answers2

0

You can use the localStorage provided by the web browser to store javascript variables to save the states of the checkbox and restore the states when teh webpage is loaded again.

This is how I did it:

function save() {
    var elems = document.getElementsByName("SubCats");
    var states = [];
    for (i = 0; i < elems.length; i++) {
        states.push(elems[i].checked);
    }

    localStorage.setItem("checkboxStates", JSON.stringify(states));
}

function restore() {
    if (localStorage.getItem("checkboxStates") !== null) {
        var states = JSON.parse(localStorage.getItem("checkboxStates"));
        var elems = document.getElementsByName("SubCats");
        for (i = 0; i < elems.length; i++) {
            elems[i].checked = states[i];
        }
    }
}

restore();

Here is the JSFiddle demo

In the demo, you can check any checkbox you like and click the Save states button. When you re run the code, you will see that it keeps the previous settings.

The flow:

When you click the Save states button, the save() function is called and it builds an array of the checkbox states sequentially and serializes them before storing them in the localStorage.

When the page is loaded again, the restore() function is triggered by default. This checks if there are states saved before. And if there are, it deserializes then and then loops through the available checkboxes, setting the states back as previously saved.

Also note that the info stored in the localStorage can be accessed on any page and therefore the data is always available.

You can also read about sessionStorage.

Ahs N
  • 8,233
  • 1
  • 28
  • 33
0

Thank you all for all the help. These are all interesting suggestions, especially the one using localStorage which I have never used and perhaps I should give it a look.

Anyway, I decided to go for the naive way. I am keeping the checked Sub-Categories in a hidden text field separated by commas and then when building the tag again I am checking for every Sub-Category whether it has been checked before.

Here is my code:

function loadSubCategories() {
    if ($("#ddlCategory").val() != "-1") {
        var SubCatsCheckboxes = {};
        SubCatsCheckboxes.url = "/BLHelpers/GetSubCats";
        SubCatsCheckboxes.type = "POST";
        SubCatsCheckboxes.data = JSON.stringify({ CategoryId: $("#ddlCategory").val() });
        SubCatsCheckboxes.datatype = "json";
        SubCatsCheckboxes.contentType = "application/json";
        SubCatsCheckboxes.success = function (SubCatsList) {
            var sub_cats = $("#SubCatsStr").val().split(",");
            $("#SubCatsDiv").empty();
            $.each(SubCatsList, function (index, value) {
                var option_to_append = "<input type=\"checkbox\" name=\"SubCats\" class=\"subcat-checkbox\" value=\"" + value.SubCategoryId + "\"";
                if ($.inArray(value.SubCategoryId.toString(), sub_cats) != -1) {
                    option_to_append += " checked "
                }
                option_to_append += ">" + value.Caption + "</option><br/>";
                $("#SubCatsDiv").append(option_to_append);
            });
        };
        $.ajax(SubCatsCheckboxes);
    }
    else {
        $("#SubCatsDiv").empty();
    }
}

Where :

<input id="SubCatsStr" name="SubCatsStr" type="hidden" value="@Model.SubCatsStr" />

is my hidden field that keeps the checked Sub Categories ids.

dsb
  • 2,347
  • 5
  • 26
  • 43