1

i have a partial view "_SearchPanel" that has year list dropdown, a classes multiselect control, (some other drop downs - ommitted) and a search button.

I want that when i change selection in year list drop down, only my classes list is refreshed/updated, and not the whole partial view on page.

So i use a JsonResult action in my controller (as opposed to the first time load)

 public JsonResult BindClasses(int yearId)
    {
        ClassRepository repClass = new ClassRepository("name=ge");
        YearRepository repYear = new YearRepository("name=ge");

        var dataClass = repClass.GetClassesByYear(yearId);
        var groupedClassOptions = dataClass.GroupBy(x => x.grade).Select(x => new OptionGroupVM()
        {
            GroupName = "Grade " + x.Key.ToString(),
            Options = x.Select(y => new OptionVM()
            {
                Value = y.classID.ToString(),
                Text = y.classname
            })
        });



        return Json(groupedClassOptions);


    }

My javascript

var dropDownYear = $('#ddlYear');
    dropDownYear.change(function(){
        $("#classList").load(url, {yearId: $(this).val()}, function(result){

            setOptions($('#classList'), @Html.Raw(Json.Encode(new List<int>(){})), result);
        });

    });

now the problem is this result is not considered as an object as was the first time (onpageload) here:

jQuery(function ($) {
   setOptions($('#classList'), @Html.Raw(Json.Encode(Model.SelectedClasses)), @Html.Raw(Json.Encode(Model.ClassOptions)));
 }

How do i correct/cast it to be considered as Model.ClassOptions(type: GroupOptionsVM List) object instead of a Json

What I have tried

    var url = '@Url.Action("BindClasses", "Maps")';
    var dropDownYear = $('#ddlYear');
    dropDownYear.change(function(){
        $("#classList").load(url, {yearId: $(this).val()}, function(result){
            @{var x = new List<OptionGroupVM>();}
            x = result;
            setOptions($('#classList'), @Html.Raw(Json.Encode(new List<int>(){})), x);

        });

    });

this gives me some syntax errors!!

UPDATE

[Referring to the previous question Stephen linked in comments] Since i had to do it for two dropdown lists with slight difference i had created setOptions function in my script

function setOptions(listBox, selected, groups) {

    // Generate options
    createGroupedOptions(listBox, selected, groups);

    // Attach plug-in
    listBox.multiselect({ enableClickableOptGroups: true, onChange: function(){
        var selectedClassItems = this.$select.val();

    } });



}

function createGroupedOptions(element, selected, groups) {

    for (var i = 0; i < groups.length; i++) {
        var group = groups[i];
        var groupElement = $('<optgroup></optgroup>').attr('label', group.GroupName);
        for (var j = 0; j < group.Options.length; j++) {
            var option = group.Options[j];
            var optionElement = $('<option></option>').val(option.Value).text(option.Text);
            if (selected) {
                if (selected.toString().indexOf(option.Value) >= 0) {
                    optionElement.attr('selected', 'selected')
                }
            } else {
                if (option.IsSelected) {
                    optionElement.attr('selected', 'selected')
                }
            }

            $(groupElement).append(optionElement);
        }
        $(element).append(groupElement);
    }

}

CALLING setOptions function

setOptions($('#classList'), @Html.Raw(Json.Encode(Model.SelectedClasses)), @Html.Raw(Json.Encode(Model.ClassOptions)));
    setOptions($('#indicatorList'), @Html.Raw(Json.Encode(Model.SelectedIndicators)), @Html.Raw(Json.Encode(Model.IndicatorOptions)));
Samra
  • 1,815
  • 4
  • 35
  • 71

2 Answers2

1

Your returning json, so using .load() makes no sense (you would typically use that when the method your calling returns a partial view).

Change your script to create the <optgroup> and <option> elements based on your data your method returns

var url = '@Url.Action("BindClasses", "Maps")';
var dropDownYear = $('#ddlYear');
dropDownYear.change(function() {
    $.post(url, { yearId: $(this).val() }, function(data) {
        $.each(data, function(index, item) {
            var group = item.GroupName;
            // use the above to build your <optgroup> element
            $.each(item.Options, function(index, item) {
                var value = item.Value;
                var text = item.Text;
                // use the above to build your <option> elements and append to the <optgroup> element
            });
            // append the <optgroup> to the <select id="classList"> element
        });
    });
});

Note the details of the code for generating the elements are in the answer to your previous question

Community
  • 1
  • 1
  • Yes. Your method is returning data as json, so you need to read that as json and loop through it to generate your elements. –  Mar 31 '17 at 00:43
  • 1
    It appears you have created a `setOptions()` function for that, so it can probably be just `$.getJSON(url, { yearId: $(this).val() }, function(data) { setOptions($('#classList'), data); });` or something similar - but you did not show the code for that function so I cannot be sure –  Mar 31 '17 at 00:45
  • That's my code from your previous question - and its named `createGroupedOptions()`, not `setOptions()` :). So your code can just be `$.getJSON(url, { yearId: $(this).val() }, function(data) { createGroupedOptions($('#classList'), null, data); });` –  Mar 31 '17 at 01:43
  • ok...and yes my setoptions function is simply calling yourfunction createGroupedOptions and also just creating a list of selected items to pass to the controller later – Samra Mar 31 '17 at 01:47
  • i understand this should be a separate question but my $.getJSON didnot get result but gave 500 error probably because it was unable to serialize... http://stackoverflow.com/questions/8026994/returning-jsonresult-results-in-500-internal-server-error – Samra Mar 31 '17 at 02:20
  • Sorry, did not check your method in detail - its a GET so it needs to be `return Json(groupedClassOptions, JsonRequestBehavior.AllowGet);`. Alternatively, it you want to make the call a POST, then replace `$.getJSON(...)` with `$.post(...)` as per edit to answer –  Mar 31 '17 at 02:24
0

You are trying to mix client side code (jQuery) with server side code (.NET) and it won't work. @Html.Raw and JsonEncode are server side methods. You can't use them after the page loads.

In essence, you need to either use jQuery for all of your page interaction and manage the state of the page on the client side or use full MVC (postback) and do everything on the server.

There are technically other options but I just wanted to address the fundamental issue with what you have tried so far.

Dan
  • 3,583
  • 1
  • 23
  • 18