asp.net-mvcasp.net-coredropdownselectlistselectlistitem

How to get items in cascade selectList after posting in ASP Core MVC


I have a cascade list for Country/Province/City and it works fine in the create and edit action except for one thing, it always becomes empty in the edit get, here is my code:

 public class LocationController : Controller
{
    public List<Country> countries = new List<Country>
    {
        new Country(){Id=1,Name="Country1"},
        new Country(){Id=2,Name="Country2"}
    };
    public List<Province> provinces = new List<Province>()
        {
            new Province() { Id = 1,CountryId = 1,Name = "Province1"},
            new Province() { Id = 2,CountryId = 2,Name = "Province2"},
        };
    public List<City> cities = new List<City>()
        {
            new City() { Id = 1,ProvinceId = 1,Name = "City1" },
            new City() { Id = 2,ProvinceId = 2,Name = "City2" },
            new City() { Id = 3,ProvinceId = 2,Name = "City3" },
        };

    public IActionResult Province(int value)
    {
        var l = provinces.Where(x => x.CountryId == value).ToList();
        return Json(l);
    }

    public IActionResult City(int value)
    {
        var c = cities.Where(c => c.ProvinceId == value).ToList();
        return Json(c);
    }
}

the Edit view:

<div class="form-group row">
                <div class="col-2">
                    <label asp-for="Country" class="col-form-label"></label>
                </div>
                <div class="col-sm-5">
                    <select id="CountryList" asp-for="Country" asp-items="@new LocationController().countries.Select(c=> new SelectListItem() {Text=c.Name,Value=c.Id.ToString() }).ToList() as IEnumerable<SelectListItem>" class="form-control">
                        <option selected disabled value="">--- Choose ---</option>
                    </select>
                </div>
            </div>
            <div class="form-group row">
                <div class="col-2">
                    <label asp-for="Province" class="col-form-label"></label>
                </div>
                <div class="col-sm-5">
                    <select id="ProvinceList" asp-for="Province" data-url="@Url.Action("Province","Location")" class="form-control">
                        <option selected disabled value="">--- Choose ---</option>
                    </select>
                </div>
            </div>
            <div class="form-group row">
                <div class="col-2">
                    <label asp-for="City" class="col-form-label"></label>
                </div>
                <div class="col-sm-5">
                    <select id="CityList" asp-for="City" data-url="@Url.Action("City","Location")" class="form-control">
                        <option selected disabled value="">--- Choose ---</option>
                    </select>
                </div>
            </div>

This is the Javascript:

@section Scripts {
    <script>
        $(function () {
            $("#CountryList").change(function () {
                $("#CityList").empty();
                var v = $(this).val();
                var url = $("#ProvinceList").data("url") + '?value=' + v;
                $.getJSON(url, function (data) {
                    $("#ProvinceList").empty();
                    $("#ProvinceList").append('<option selected disabled value="">--- Choose ---</option>');
                    $.each(data, function (i, item) {
                        $("#ProvinceList")
                            .append($("<option>").text(item.name).val(item.id));
                    });
                });
            });
            $("#ProvinceList").change(function () {
                var v = $(this).val();
                var url = $("#CityList").data("url") + '?value=' + v;
                $.getJSON(url, function (data) {
                    $("#CityList").empty();
                    $("#CityList").append('<option selected disabled value="">--- Choose ---</option>');
                    $.each(data, function (i, item) {
                        $("#CityList")
                            .append($("<option>").text(item.name).val(item.id));
                    });
                });
            });
        });
        $('#formId').submit(function () {
            $('#CountryList option').val(function () {
                return $(this).text();
            });
            $('#ProvinceList option').val(function () {
                return $(this).text();
            });
            $('#CityList option').val(function () {
                return $(this).text();
            });
        });
    </script>
}

and of course in the get action I tried to get the user's location from the database, and its working in the get:

 [HttpGet]
    public async Task<IActionResult> Edit(string id)
    {
        var user = await _userManager.FindByIdAsync(id);
        EditUserViewModel modelVM = new EditUserViewModel
        {
            Country = user.Country,
            Region = user.Region,
            City = user.City,
        };
        return View(modelVM);
    }

Get edit action

but in the view the province/region and city are empty:

Edit view

If I click update province and city will be null.


Solution

  • Here is a working demo about how to pass the selected item to the action:

    Model:

    public class Country
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Province
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int CountryId { get; set; }
    }
    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int ProvinceId { get; set; }
    }
    

    Update:

    It seems you want to edit one user and the edit view would display the user's default city,province and country.So I think your js is no need in edit view.

    Here is a working demo like below:

    Model:

    public class UserProfile
    {
        public string Id { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
        public string Province { get; set; }
    }
    public class EditUserViewModel
    {
        public string City { get; set; }
        public string Country { get; set; }
        public  string Province { get; set; }
    }
    

    Index.cshtml(display the user data):

    @model IEnumerable<UserProfile>
    <table>
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Country)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Province)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.City)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Country)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Province)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.City)
                    </td>
                    <td>
                        <a asp-action="Edit" asp-route-id="@item.Id">Edit</a>               
                    </td>
                </tr>
            }
        </tbody>
    </table>
    

    Edit.cshtml:

    @model EditUserViewModel
    <form id="formId" asp-controller="Location" asp-action="Edit">
        <div class="form-group row">
            <div class="col-2">
                <label asp-for="Country" class="col-form-label"></label>
            </div>
            <div class="col-sm-5">
    
                //change here....
                <select id="CountryList" asp-for="Country" asp-items="@ViewBag.Country" class="form-control">
                    <option selected disabled value="">--- Choose ---</option>
                </select>
            </div>
        </div>
        <div class="form-group row">
            <div class="col-2">
                <label asp-for="Province" class="col-form-label"></label>
            </div>
            <div class="col-sm-5">
    
                //change here....
                <select id="ProvinceList" asp-for="Province" asp-items="@ViewBag.Province" data-url="@Url.Action("Province","Location")" class="form-control">
                    <option selected disabled value="">--- Choose ---</option>
                </select>
            </div>
        </div>
        <div class="form-group row">
            <div class="col-2">
                <label asp-for="City" class="col-form-label"></label>
            </div>
            <div class="col-sm-5">
    
                //change here....
                <select id="CityList" asp-for="City" asp-items="@ViewBag.City" data-url="@Url.Action("City","Location")"  class="form-control">
                    <option selected disabled value="">--- Choose ---</option>
                </select>
            </div>
        </div>
        <input type="submit" value="aaa" />
    </form>
    
    @section Scripts
    {
        <script>
            $(function () {
                $("#CountryList").change(function () {
                    $("#CityList").empty();
                    var v = $(this).val();
                    var url = $("#ProvinceList").data("url") + '?value=' + v;
                    $.getJSON(url, function (data) {
                        $("#ProvinceList").empty();
                        $("#ProvinceList").append('<option selected disabled value="">--- اختر ---</option>');
                        $.each(data, function (i, item) {
                            $("#ProvinceList")
                                .append($("<option>").text(item.name).val(item.id));
                        });
                    });
                });
                $("#ProvinceList").change(function () {
                    var v = $(this).val();
                    var url = $("#CityList").data("url") + '?value=' + v;
                    $.getJSON(url, function (data) {
                        $("#CityList").empty();
                        $("#CityList").append('<option selected disabled value="">--- اختر ---</option>');
                        $.each(data, function (i, item) {
                            $("#CityList")
                                .append($("<option>").text(item.name).val(item.id));
                        });
                    });
                });
            });
            $('#formId').submit(function () {
                $('#CountryList option').val(function () {
                    return $(this).text();
                });
                $('#ProvinceList option').val(function () {
                    return $(this).text();
                });
                $('#CityList option').val(function () {
                    return $(this).text();
                });
            });
        </script>
    }
    

    HomeController:

    public class HomeController : Controller
    {      
        private List<UserProfile> users = new List<UserProfile>()
        {
            new UserProfile(){Id="1",Province="1",Country="1",City="1"},
            new UserProfile(){Id="2",Province="2",Country="2",City="3"},
        };    
        public IActionResult Index()
        {
            return View(users);
        }
    
        [HttpGet]
        public async Task<IActionResult> Edit(string id)
        {
            var user = users.Where(a => a.Id == id).FirstOrDefault();          
            ViewBag.Province = new SelectList(new LocationController().provinces,"Id","Name", user.Province);
            ViewBag.City = new SelectList(new LocationController().cities,"Id","Name", user.City);
            ViewBag.Country = new SelectList(new LocationController().countries,"Id","Name", user.Country);
            EditUserViewModel modelVM = new EditUserViewModel
            {
                Country = user.Country,
                Province = user.Province,
                City = user.City,
            };
            return View(modelVM);
        }
        [HttpPost]
        public IActionResult Edit(string city, string province, string country)
        {
            return RedirectToAction("Index");
        }
    
    }
    

    Result: enter image description here