在 mvc 中加载 2 下拉列表的更好方法
better way to load 2 dropdown in 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>
使用 Knockout 怎么样?
Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model
您必须为您的城市使用 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\""})
不要被 \"\" 吓到,因为 "
是一个转义字符,我们必须告诉剃刀我想通过在它前面使用 \ 来使用 "。
您可以找到更多关于淘汰赛的信息:Knockout
并与剃须刀混合:Razor and Knockout
Ps:是的,使用敲除会暂停我们使用 Razor 和 Mvc。您必须编写另一个 ViewModel 。但是像这种情况 ko 是有帮助的。混合剃须刀和挖空器是您的另一种选择。
这是一个正确的方法,但您可以简化您的 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 会更小。
假设城市列表不太长,我将在不刷新页面的情况下执行此操作。
我假设您可以为 return 字典创建一个 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);
}
这样当状态改变时cities字段会立即更新而不需要回调。
你使用 ajax 的方法很好,但我会推荐一些更好的做法,包括使用具有 StateID
、CityID
、StateList
和 [= 属性的视图模型18=],并使用 Unobtrusive JavaScript 而不是用行为污染你的标记,并使用 null
值而不是 0
生成第一个("please select")选项,所以它可以与 [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 个城市),您可以缓存第一次调用的结果以避免重复调用 selections 可能包括来自同一州的城市。
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
});
免责声明:这不是代码答案,还有很多其他答案。
我认为让自己开心的最好方法是将 UI 页面与数据分开 => 将它们变成 API 调用:
- /GetCities
- /GetStates
现在您只需在 Razor 呈现页面时将 select 留空即可。并使用 Jquery/Bootstrap 插件创建一个 AJAX select 框。
这样当用户停止输入他的搜索时,这个搜索字符串可以通过 AJAX 调用发送(例如:/GetStates?search=test
),然后一个小的结果集可以发送回网站。
这给出:
- 更好地分离服务端代码
- 更好的用户体验。
- 较小的页面加载(因为您不再在用户请求页面时向用户发送所有选项,仅当他打开 select 框时)。
这是我在页面加载状态和城市下拉列表中加载的方式:
我的控制器方法:
这是加载页面时调用的第一个方法。
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>
使用 Knockout 怎么样?
Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model
您必须为您的城市使用 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\""})
不要被 \"\" 吓到,因为 "
是一个转义字符,我们必须告诉剃刀我想通过在它前面使用 \ 来使用 "。
您可以找到更多关于淘汰赛的信息:Knockout
并与剃须刀混合:Razor and Knockout
Ps:是的,使用敲除会暂停我们使用 Razor 和 Mvc。您必须编写另一个 ViewModel 。但是像这种情况 ko 是有帮助的。混合剃须刀和挖空器是您的另一种选择。
这是一个正确的方法,但您可以简化您的 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 会更小。
假设城市列表不太长,我将在不刷新页面的情况下执行此操作。
我假设您可以为 return 字典创建一个 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);
}
这样当状态改变时cities字段会立即更新而不需要回调。
你使用 ajax 的方法很好,但我会推荐一些更好的做法,包括使用具有 StateID
、CityID
、StateList
和 [= 属性的视图模型18=],并使用 Unobtrusive JavaScript 而不是用行为污染你的标记,并使用 null
值而不是 0
生成第一个("please select")选项,所以它可以与 [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 个城市),您可以缓存第一次调用的结果以避免重复调用 selections 可能包括来自同一州的城市。
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
});
免责声明:这不是代码答案,还有很多其他答案。
我认为让自己开心的最好方法是将 UI 页面与数据分开 => 将它们变成 API 调用:
- /GetCities
- /GetStates
现在您只需在 Razor 呈现页面时将 select 留空即可。并使用 Jquery/Bootstrap 插件创建一个 AJAX select 框。
这样当用户停止输入他的搜索时,这个搜索字符串可以通过 AJAX 调用发送(例如:/GetStates?search=test
),然后一个小的结果集可以发送回网站。
这给出:
- 更好地分离服务端代码
- 更好的用户体验。
- 较小的页面加载(因为您不再在用户请求页面时向用户发送所有选项,仅当他打开 select 框时)。