更好的方法来加载2下拉列表中的MVC

这是我如何加载页面加载状态和城市下拉菜单:

我的控制器方法

这是加载页面时调用的第一个方法。

public ActionResult Index() { var states = GetStates(); var cities = Enumerable.Empty<SelectListItem>(); ViewBag.States = states; ViewBag.Cities = cities; } private IEnumerable<SelectListItem> GetStates() { using (var db = new DataEntities()) { return db.States.Select(d => new SelectListItem { Text = d.StateName, Value =d.Id.ToString() }); } } [HttpGet] public ActionResult GetCities(int id) { using (var db = new DataEntities()) { var data = db.Cities.Where(d=>d.StateId==id).Select(d => new { Text = d.CityName, Value = d.Id }).ToList(); return Json(data, JsonRequestBehavior.AllowGet); } } 

我的观点

 IEnumerable<SelectListItem> States = ViewBag.States; IEnumerable<SelectListItem> Cities = ViewBag.Cities; @Html.DropDownList("State", States, "Select State", new { onchange="loadCities(this)"}) @Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity"}) function loadCities(obj) { $.ajax({ url: "/Home/GetCities", data: { id: $(obj).val() }, contentType:"application/json", success:function(responce){ var html = '<option value="0">Select City</option>'; $(responce).each(function () { html += '<option value="'+this.Value+'">'+this.Text+'</option>' }); $("#ddlCity").html(html); } }); } 

任何更好的方式,然后加载状态和城市下拉?

 public class HomeController : Controller { public ActionResult Index(int id=0) { Person model = null; var states = GetStates().ToList(); var cities = Enumerable.Empty<SelectListItem>(); if (id > 0) { using (var db = new DataEntities()) { model = db.People.Include("City").FirstOrDefault(d => d.Id == id); if (model == null) model = new Person(); else { states.First(d => d.Value == model.City.StateId.ToString()).Selected = true; cities = db.Cities.Where(d => d.StateId == model.City.StateId).ToList().Select(d => new SelectListItem { Text = d.CityName,Value=d.Id.ToString(),Selected=d.Id==model.CityId }); } } } else { model = new Person(); } ViewBag.States = states; ViewBag.Cities = cities; ViewBag.Persons = GetPersons(); return View(model); } [HttpGet] public ActionResult GetCities(int id) { using (var db = new DataEntities()) { var data = db.Cities.Where(d=>d.StateId==id).Select(d => new { Text = d.CityName, Value = d.Id }).ToList(); return Json(data, JsonRequestBehavior.AllowGet); } } public ActionResult SavePersonDetail([Bind(Exclude = "Id")] Person model) { // var employeeDal= new Emploee(); //employee.firstname=model. if (ModelState.IsValid) { var Id = model.Id; int.TryParse(Request["Id"], out Id); using (var db = new DataEntities()) { if (Id > 0) { var person = db.People.FirstOrDefault(d => d.Id == Id); if (person != null) { model.Id = Id; db.People.ApplyCurrentValues(model); } } else { db.People.AddObject(model); } db.SaveChanges(); } } if (!Request.IsAjaxRequest()) { ViewBag.States = GetStates(); ViewBag.Persons = GetPersons(); ViewBag.Cities = Enumerable.Empty<SelectListItem>(); return View("Index"); } else { return PartialView("_personDetail",GetPersons()); } } public ActionResult Delete(int id) { using (var db = new DataEntities()) { var model = db.People.FirstOrDefault(d => d.Id == id); if (model != null) { db.People.DeleteObject(model); db.SaveChanges(); } } if (Request.IsAjaxRequest()) { return Content(id.ToString()); } else { ViewBag.States = GetStates(); ViewBag.Persons = GetPersons(); ViewBag.Cities = Enumerable.Empty<SelectListItem>(); return View("Index"); } } private IEnumerable<SelectListItem> GetStates() { using (var db = new DataEntities()) { return db.States.ToList().Select(d => new SelectListItem { Text = d.StateName, Value =d.Id.ToString() }); } } private IEnumerable<Person> GetPersons() { using (var db = new DataEntities()) { return db.People.Include("City").Include("City.State").ToList(); } } public ActionResult HomeAjax() { ViewBag.States = GetStates(); ViewBag.Cities = Enumerable.Empty<SelectListItem>(); using (var db = new DataEntities()) { var data = db.States.Include("Cities").Select(d => new { Id = d.Id, Name = d.StateName, Cities = d.Cities.Select(x => new { Id=x.Id,Name=x.CityName}) }).ToList(); ViewBag.CityStateJson = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(data); } ViewBag.Persons = GetPersons(); return View(); } } @model IEnumerable<Person> <div> <table> <tr> <th> First Name </th> <th> Last Name </th> <th> Email </th> <th> City </th> <th> State </th> <th> Edit </th> </tr> @if (Model.Count() == 0) { <tr> <td colspan="6"> <h3>No data available</h3> </td> </tr> } else { foreach (var item in Model) { <tr data-id="@item.Id"> <td data-id="fn">@item.FirstName</td> <td data-id="ln">@item.LastName</td> <td data-id="email">@item.Email</td> <td data-id="cn">@item.CityName<input type="hidden" value="@item.CityId" /></td> <td>@item.StateName</td> <td> @if (ViewBag.Title == "Home Ajax" || Request.IsAjaxRequest()) { <a href="javascript:void(0);" onclick="Edit(this,@item.Id);">Update</a> <span>@Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions {OnSuccess="deleteSuccess",OnBegin="showLoader",OnComplete="hideLoader" })</span> } else { <span>@Html.ActionLink("Update", "Index", new { id = item.Id })</span> <span>@Html.ActionLink("Delete", "Delete", new { id = item.Id })</span> } </td> </tr> } } </table> </div> @model Person @{ ViewBag.Title = "Home Ajax"; IEnumerable<Person> persons = ViewBag.Persons; IEnumerable<SelectListItem> States = ViewBag.States; IEnumerable<SelectListItem> Cities = ViewBag.Cities; IEnumerable<State> fullStates=ViewBag.CityStates; } @section featured { <section class="featured"> <div class="content-wrapper"> <hgroup class="title"> <h1>@ViewBag.Title.</h1> </hgroup> </div> </section> } @section styles{ <style type="text/css"> td,th { border:1px solid; padding:5px 10px; } select { padding:5px 2px; width:310px; font-size:16px; } </style> } @section scripts{ @Scripts.Render("~/bundles/jqueryval") <script type="text/javascript"> var jsonArray = @Html.Raw(ViewBag.CityStateJson) function clearValues() { $("input[type='text'],select").val(''); $("input[type='hidden'][name='Id']").val(0); } function loadCities(obj) { for (var i = 0; i < jsonArray.length; i++) { if (jsonArray[i].Id == parseInt($(obj).val())) { fillCity(jsonArray[i].Cities); break; } } } function Edit(obj, Id) { // alert("hi") $("input[type='hidden'][name='Id']").val(Id); var tr = $(obj).closest("tr"); $("#txtfirstName").val($("td[data-id='fn']", tr).text().trim()); $("#txtlastName").val($("td[data-id='ln']", tr).text().trim()); $("#txtemail").val($("td[data-id='email']", tr).text().trim()); var city = $("td[data-id='cn'] input[type='hidden']", tr).val(); var state; for (var i = 0; i < jsonArray.length; i++) { for (var j = 0; j < jsonArray[i].Cities.length; j++) { if (jsonArray[i].Cities[j].Id == parseInt(city)) { state = jsonArray[i].Id; break; } } if (state) { fillCity(jsonArray[i].Cities); break; } } $("#ddlState").val(state); $("#ddlCity").val(city); } function fillCity(obj) { var html = '<option value="0">Select City</option>'; $(obj).each(function () { html += '<option value="' + this.Id + '">' + this.Name + '</option>' }); $("#ddlCity").html(html); } function deleteSuccess(responce) { alert("record deleted successfully"); $("tr[data-id='" + responce + "']").remove(); } function insertSuccess() { alert("Record saved successfully"); clearValues(); } function showLoader() { $("#overlay").show(); } function hideLoader() { $("#overlay").hide(); } </script> } <h3>Add Personal Detail</h3> @using (Ajax.BeginForm("SavePersonDetail", "Home", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "personList" ,OnSuccess="insertSuccess",OnBegin="showLoader",OnComplete="hideLoader"})) { @Html.HiddenFor(m => m.Id); <ol class="round"> <li> @Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName, new { id = "txtfirstName" }) @Html.ValidationMessageFor(m => m.FirstName) </li> <li> @Html.LabelFor(m => m.LastName) @Html.TextBoxFor(m => m.LastName, new { id = "txtlastName" }) @Html.ValidationMessageFor(m => m.LastName) </li> <li> @Html.LabelFor(m => m.Email) @Html.TextBoxFor(m => m.Email, new { id = "txtemail" }) @Html.ValidationMessageFor(m => m.Email) </li> <li> @Html.Label("State") @Html.DropDownList("State", States, "Select State", new { onchange = "loadCities(this)", id = "ddlState" }) </li> <li> @Html.LabelFor(m => m.CityId) @Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id = "ddlCity" }) @Html.ValidationMessageFor(m => m.CityId) </li> </ol> <input type="submit" value="Save" /> <input type="button" value="Cancel" onclick="clearValues();"/> } <h2> Person List </h2> <div style="position:fixed;text-align:center;top:0;bottom:0;left:0;right:0;z-index:10;background-color:black;opacity:0.6;display:none;" id="overlay"> <img style="position:relative;top:370px" src="~/Images/ajax-loader.gif" /> </div> <div id="personList"> @Html.Partial("_personDetail", persons) </div> 

尽pipe我会推荐一些更好的做法,包括使用具有StateIDCityID StateListCityList属性的视图模型,并且使用Unobtrusive JavaScript而不是污染带有行为的标记,并生成第一个(“请select” )选项的null值而不是0所以它可以与[Required]属性一起使用

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? 

脚本

 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)); }); }); }); 

如果您正在渲染多个项目(例如,要求用户select他们访问的最后10个城市),则可以caching第一个呼叫的结果以避免重复呼叫,其中他们的select可能包括来自同一州的城市。

 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; ..... }); } }); 

最后,为了回应你关于不使用Ajax的评论,你可以将所有的城市都传递给视图,并将它们分配给一个javascript数组。 如果你有几个国家,每个都有几个城市,我只会推荐这个。 它是平衡轻微额外的初始加载时间与ajax调用的轻微延迟的问题。

在控制器中

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

在视图(脚本)

 // 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 }); 

这是一个正确的方法,但是你可以简化你的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); }); } 

进一步可能的简化:添加默认项(select城市)服务器端,所以你的JavaScript将会更小。

假设城市列表不是太长,我不用刷新页面就可以做到这一点。 我假设你可以创build一个GetStatesAndCities方法来返回一个字典。

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

然后在视图中:

 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); } 

这样当状态更新的时候立即更新城市字段而不需要callback。

声明:这不是一个代码的答案,还有很多其他的答案。

我认为最好的方式来保持自己的快乐,从数据分开的UI页面=>把他们变成API调用:

  • / GetCities
  • / GETSTATES

现在你可以简单地把select空的Razor渲染成页面。 并使用Jquery / Bootstrap插件创build一个AJAXselect框。

这样,当用户停止input他的search时,这个searchstring可以通过AJAX调用发送(例如: /GetStates?search=test ),然后一个小的结果集可以发送回网站。

这给了:

  • 更好地分离服务代码
  • 更好的用户体验。
  • 较小的页面加载(因为你不再发送所有的选项给用户,当他请求页面,只有当他打开select框)。

如何使用淘汰赛?

Knockout是一个JavaScript库,可帮助您使用干净的底层数据模型创build丰富,响应式的显示和编辑器用户界面

你必须为你的城市使用ajax。 但是用淘汰赛你不需要写

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

在你的javascript.Knockout使它简单。

你可以简单地写:

  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()); 

就这样。 但是你必须将你的数据绑定到html元素。 而不是使用: @Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity"})

您可以使用:

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

或者你可以混合剃刀和淘汰赛:

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

State发生变化时,还需要调用GetCities ,您可以:

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

不要被这个“\”这个东西吓倒,因为"是一个转义字符,我们必须对它使用\”来使用剃刀。

你可以find更多关于淘汰赛的信息: 淘汰赛

和剃刀混合: 剃刀和敲击

Ps:是的使用淘汰赛暂停我们从剃刀和Mvc。 你必须写另一个ViewModel。 但是像这样的情况ko是有帮助的。 混合razor和淘汰赛是另一种select。