better way to load 2 dropdown in mvc

后端 未结 5 502
没有蜡笔的小新
没有蜡笔的小新 2020-11-22 03:05

This is how i am loading on page load state and city dropdown:

My Controller method:

This is the first method which is calling when page is

相关标签:
5条回答
  • 2020-11-22 03:18

    You approach using ajax is fine although I would recommend a few better practices including using a view model with properties for StateID, CityID StateList and CityList, and using Unobtrusive JavaScript rather than polluting you markup with behavior, and generating the first ("please select") option with a null value rather than 0 so it can be used with the [Required] attribute

    HTML

    @Html.DropDownList(m => m.StateID, States, "Select State") // remove the onchange
    @Html.DropDownListFor(m => m.CityID, Cities, "Select City") // why change the default ID?
    

    SCRIPT

    var url = '@Url.Action("GetCities", "Home")'; // use the helper (dont hard code)
    var cities = $('#CityID'); // cache the element
    $('#StateID').change(function() {
      $.getJSON(url, { id: $(this).val() }, function(response) {
        // clear and add default (null) option
        cities.empty().append($('<option></option>').val('').text('Please select'));
        $.each(response, function(index, item) {
          cities.append($('<option></option>').val(item.Value).text(item.Text));
        });
      });
    });
    

    If you were rendering multiple items (say you were asking the user to select their last 10 cities they visited), you can cache the result of the first call to avoid repeated calls where their selections may include cities from the same state.

    var cache = {};
    $('#StateID').change(function() {
      var selectedState = $(this).val();
      if (cache[selectedState]) {
        // render the options from the cache
      } else {
        $.getJSON(url, { id: selectedState }, function(response) {
          // add to cache
          cache[selectedState] = response;
          .....
        });
      }
    });
    

    Finally, in response to your comments regarding doing it without ajax, you can pass all the cities to the view and assign them to a javascript array. I would only recommend this if you have a few countries, each with a few cities. Its a matter of balancing the slight extra initial load time vs the slight delay in making the ajax call.

    In the controller

    model.CityList = db.Cities.Select(d => new { City = d.CountryID, Text = d.CityName, Value = d.Id }).ToList();
    

    In the view (script)

    // assign all cities to javascript array
    var allCities= JSON.parse('@Html.Raw(Json.Encode(Model.CityList))');
    $('#StateID').change(function() {
      var selectedState = $(this).val();
      var cities = $.grep(allCities, function(item, index) {
        return item.CountryID == selectedState;
      });
      // build options based on value of cities
    });
    
    0 讨论(0)
  • 2020-11-22 03:19

    Here's how I'd do it without the page refresh, assuming the list of cities isn't too long. I'm assuming you can create a GetStatesAndCities method to return a Dictionary.

    public ActionResult Index()
    {
      Dictionary<string, List<String>> statesAndCities = GetStatesAndCities();
      ViewBag.StatesAndCities = Json(statesAndCities);
    }
    

    Then in the view:

    var states = JSON.parse(@ViewBag.StatesAndCities);
    
    function loadCities(obj) {
        var cities = states[$(obj).val()];
        var html = '<option value="0">Select City</option>';
        $(cities).each(function () {
            html += '<option value="'+this.Value+'">'+this.Text+'</option>'
        });
        $("#ddlCity").html(html);
    }
    

    This way when the state is changed the cities field with update immediately with no need for callback.

    0 讨论(0)
  • 2020-11-22 03:29

    How about using Knockout?

    Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model

    You have to use ajax for your cities. But with knockout you dont need to write

    var html = '<option value="0">Select City</option>'; $(responce).each(function () { html += '<option value="'+this.Value+'">'+this.Text+'</option>'}); $("#ddlCity").html(html);

    in your javascript.Knockout makes it simple.

    You can simply write:

            function CityModel() {
            var self = this; // that means this CityModel
            self.cities = ko.observableArray([]);
            self.getCities = function () {
                $.ajax({
                    url: "/Home/GetCities",
                    data: { id: $(obj).val() },
                    contentType: "application/json",
                    success: self.cities
                });
            }
        }
        ko.applyBindings(new CityModel());
    

    thats all. But you have to bind your data into html elements. Instead of using : @Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity"})

    You can use:

        <select data-bind="options:cities,optionsValue:"Id",optionsText:"CityName",optionsCaption:"Select City""></select>
    

    or you can mix razor and knockout:

    @Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity",data_bind:"options:cities,optionsValue:\"Id\",optionsText:\"CityName\""})
    

    One more thing you have to call GetCities when State changes, you can :

    @Html.DropDownList("State", States, "Select State", new {data_bind:"event:\"change\":\"$root.GetCities\""})
    

    Dont be scare with \"\" things this because " is an escape character and we have to say to razor i want to use " by using \ before it.

    You can find more info about knockout :Knockout

    And mixing with razor: Razor and Knockout

    Ps: yes using knockout is suspend us from Razor and Mvc. You have to write another ViewModel . But like this situations ko is helpful. Mixing razor and knockout is another option for you.

    0 讨论(0)
  • 2020-11-22 03:30

    disclaimer: This is not a code answer, there are plenty other answers.

    I think best way to keep yourself happy to seperate UI pages from data => turn them into API calls:

    • /GetCities
    • /GetStates

    Now you can simply leave the select's empty on Razor rendering the page. And use a Jquery/Bootstrap plugin to create an AJAX select box.

    This way when the user stops typing his search, this search string can than be send with the AJAX call (eg: /GetStates?search=test) and then a small result set can be send back to the website.

    This gives:

    • Better separation in serveside code
    • Better User eXperience.
    • Smaller page loads (since you no longer send all the options to user when he requests the page, only when he opens the select box).
    0 讨论(0)
  • 2020-11-22 03:42

    This is a correct approach, but you can simplify your javascript:

    function loadCities(obj) {
        $.getJSON("/Home/GetCities", function (data) {
            var html = '<option value="0">Select City</option>';
            $(data).each(function () {
                  html += '<option value="'+this.Value+'">'+this.Text+'</option>'
            });
            $("#ddlCity").html(html);
        });
    }
    

    Further possible simplification: Add the default item (Select City) server-side, so your javascript will be smaller.

    0 讨论(0)
提交回复
热议问题