0

I have a multi select list

                    <div id="statusWrapper" class="row" style="left:2px">
                         @Html.LabelFor(model => model.Countries, htmlAttributes: new { @class = "col-sm-4 label-box required" })
                         <div class="col-md-6 input-group" style="left:2px; width: 47%;">
                             @Html.ListBoxFor(model => model.SelectedCountryIds, (MultiSelectList)Model.Countries, new { @class = "multiselect form-control", multiple = "multiple", id = "cbJT" })
                         </div>
                 </div>
                 <div class="row" style="padding:2px">
                     @Html.Label("City", new { @class = "col-sm-4 label-box required" })
                     <div class="col-sm-6 value-box" style="padding-left:2px; padding-top: 2px;">
                         @Html.DropDownListFor(model => model.CityId, Enumerable.Empty<SelectListItem>(), "Select", new { @class = "combobox form-control"})
                         @Html.ValidationMessageFor(x => x.CityId)
                     </div>
                 </div>

The first is a multiselect dropdown that gets populated on page load. Second drop down is dynamically populated whenever there is a selection (or deselection) in the previous list.

 $('#cbJT').on('change', function (e) {
            $('#CityId').empty();
            $.each(this.selectedOptions, function (id, opt) {
                $('<option>').val(opt.value).text(opt.text).appendTo('#CityId');
            });
 );

This successfully appends to the select tag, but drop down list is unable to expand, like it is empty, even though after a few selections, it holds values of a few countries.

And the generated HTML after a few selections: enter image description here

Mefhisto1
  • 2,188
  • 7
  • 34
  • 73
  • 1
    you better use jquery to do this – Frebin Francis Oct 16 '17 at 12:14
  • You need to handle the `.change()` event of the 1st dropdownlist and make an ajax call to populate the 2nd. As a side note you do not need the `(MultiSelectList)` - just needs to be `Model.Contries` –  Oct 16 '17 at 12:15
  • Refer [this answer](https://stackoverflow.com/questions/33247717/how-to-keep-cascade-dropdownlist-selected-items-after-form-submit) for an example. In your case, the method you make the ajax call to just needs a parameter which is an `IEnumerable` for the selected countries –  Oct 16 '17 at 12:19

2 Answers2

1

You need to listen to the change event of the first dropdown and read the selected values. For the multi select, this will be an array of values which has the selected option value attribute values, and you may send it to your server via ajax where an action method can use this array of ids to give you a list of cities belongs to those country ids.

$(document).ready(function() {

    $("#cbJT").change(function() {

        var v = $(this).val();
        $.post("@Url.Action("GetCities", "Home")",{ countryIds: v },function (result) {

                $("#CityId").html("");
                $.each(result,function(a, b) {                        
                       $('<option>').val(b.Value).text(b.Text).appendTo('#CityId');
                });    
        });
    });

});

Here i am using @Url.Action method inside the javascript to generate the correct relative path to the action method. It will work if your script is inside a razor view. If it is inside an external javascript file. follow the approach mentioned in this post.

Assuming you have a GetCities action method which accepts this array of ids and return a list of SelectListItem objects. The below sample code assumes that you use Entity framework as your data access technology and db.Cities will give you DbSet<Citiy> collection.

[HttpPost]
public ActionResult GetCities(int[] countryIds)
{    
    var cities = db.Cities
                   .Where(f => countryIds.Contains(f.CountryId))
                   .Select(f => new SelectListItem() { Value = f.Id.ToString(),
                                                       Text = f.Name })
                   .ToList();

    return Json(cities);

}

Also, unless there is a compelling reason, i would not give a different Id value for the dropdown. The helper method will generate the correct (and meaningful to the context) Id value from the property name (SelectedCountriesIds)

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • I took the way you proposed. However, the #CityId dropdown list always remains empty (and not expandable), even though the items variable is ok. @Html.DropDownListFor(model => model.CityId, Enumerable.Empty(), "Select", new { @class = "combobox form-control"}) – Mefhisto1 Oct 16 '17 at 12:40
  • is your ajax call successful ? Are you getting the expected results from that ? Check your browser console – Shyju Oct 16 '17 at 12:41
  • Yes, my response is good, containing all info, and the html string looks fine. However, the last part, appending to the drop down doesn't work, as said before – Mefhisto1 Oct 16 '17 at 12:42
  • i assume, then you probably are missing a quotes when building the select option. can you do a `console.log(items)` and verify that? – Shyju Oct 16 '17 at 12:44
  • it looks something like this: "" – Mefhisto1 Oct 16 '17 at 12:45
  • That looks correct. Is your second dropdown Id "CityId" ? BTW, i updated the answer to avoid the string concatenation. – Shyju Oct 16 '17 at 12:50
  • Take a look at this fiddle and compare with your code and see what you are missing http://jsbin.com/supovawaxe/edit?html,js,output – Shyju Oct 16 '17 at 12:53
  • Everything is correct. It is probably due to asp.net, and how it generates HTML. As said this is what my razor looks like: @Html.DropDownListFor(model => model.CityId, Enumerable.Empty(), "Select", new { @class = "combobox form-control"}) So i'm not sure if this Enumerable.Empty confuses it somehow – Mefhisto1 Oct 16 '17 at 12:55
  • That should generate an empty SELECT element when razor execute that code. Check the view source of the page to confirm your SELECT element name is `CityId` also double check your page has any script errors. – Shyju Oct 16 '17 at 13:00
  • Both checks are fine - there is a select element with the same ID, and there are no script errors on the page.. – Mefhisto1 Oct 16 '17 at 13:04
  • Do you have more than one element with same Id value ? That is invalid HTML – Shyju Oct 16 '17 at 13:04
  • After inspecting the auto generated HTML, option tags are appended to the select, however, they are all empty, after selecting five countries I get five times this: – Mefhisto1 Oct 16 '17 at 13:07
  • Inspect the json response you are getting from the ajax call. It should match with what you see in the filddle i shared earlier. Each item should have a `Value` and `Text` property – Shyju Oct 16 '17 at 13:08
  • Unfortunately, I guess this just doesn't work with ASP.NET. After double checking, it populates correctly the select with multiple options and their values. However, ASP.NET generates one more input element for this, it doesn't have the ID, but the name is CityId. So even though the select tag is populated correctly, it is unable to expand the drop down list, like it's empty.. – Mefhisto1 Oct 16 '17 at 13:14
  • What you mean **this just doesn't work with ASP.NET.** ??? As per the code you shared in the question, the helper method will generate only one SELECT element with Id and name property CityId. Asp.NET simply does not generate random control in your page. – Shyju Oct 16 '17 at 13:16
  • I guess the simplest thing is to edit my question with all the code and generated HTML.. – Mefhisto1 Oct 16 '17 at 13:18
  • I see your problem. You have 2 HTML elements with CityId as the Id value. That is invalid HTML. Ids of elements should be unique across the document. Why do you have the hidden input for CityId ? Just remove it. – Shyju Oct 16 '17 at 13:27
  • Yes, But i posted all of my razor-html code, rest was generated by asp.net. So how / where do I remove unnecessary html? – Mefhisto1 Oct 16 '17 at 13:29
  • asp.net does not randomly generate input elements for you. There is some code in your view file which generates the markup. look for `CityId`. Probably there is something like `@Html.Hiddenfor(x=>x.CityId)` or `` in your view. – Shyju Oct 16 '17 at 13:34
-1

You can post the form to the server and use the values in the new page:

//psuedo c#
class Controller {
  IView Page2(List<string> selectedOptions){
     return View("Page2", selectedOptions)
  }
}

//razor
@foreach(var item in Model){
   <option>@item</option
}

Otherwise if you want direct feedback, its much easier to do this with java-script (and feels much nicer to the user instead of doing a page refresh).

Joel Harkes
  • 10,975
  • 3
  • 46
  • 65