ASP MVC 5 - 使用级联下拉列表动态添加多个局部视图
ASP MVC 5 - Multiple Partial Views added Dynamically with cascading DropDown Lists
我面临的问题与这个旧问题类似 post cascading dropdown for dynamically added row。我正在使用 "BeginCollectionItemCore" NuGet 包来设置一组局部视图,因此我的控件具有唯一的 ID。问题是,我只能得到第一个局部视图来响应下拉列表的变化。随后的下拉列表不会级联。我已经尝试在部分视图和主视图中使用脚本,但两者的最终结果相同,只有第一个部分会级联。这是我的代码...
主视图 HTML:
@model IEnumerable<RCRTCWA.DATA.DAL.tbl_RCRTimeCards>
@{
ViewBag.Title = "Index";
}
<h2>Time Card</h2>
@using (Html.BeginForm())
{
<div id="TimeCardLines">
@foreach (var item in Model)
{
Html.RenderPartial("_TimeCardRow", item);
}
</div>
}
@Html.ActionLink("Add more time...", "_TimeCardRow", new { ViewContext.FormContext.FormId }, new { id = "addTime"})
主视图脚本:
<script>
$(document).ready(function () {
debugger;
$("#addTime").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#TimeCardLines").append(html); }
});
return false;
});
//var index = "";
$(".timecardrow").focusin(function () {
var ti = $(this).find("[name='timecardrows.index']");
var index = ti.val();
$("#timecardrows_" + index + "__HRS_EndTime").timepicker({
defaultTime: 'now',
minTime: '6:00am',
maxTime: '7:00pm'
});
$("#timecardrows_" + index + "__HRS_StartTime").timepicker({
defaultTime: 'now',
minTime: '6:00am',
maxTime: '7:00pm'
});
//$("#.Line_TimeCard").ajaxSuccess(function () {
// $.getJSON("/TimeCard/AddTimeCardRow/", $("#.Success").html(data).show());
//});
$("#timecardrows_" + index + "__WOTicketNo").change(function () {
var tktid = $(this).val();
$("#timecardrows_" + index + "__WOTicketRepLineNo").empty();
$.ajax({
url: "/TimeCard/GetRepairLines/",
data: { ticket: tktid },
cache: false,
type: "POST",
success: function (data) {
$.each(data, function (i, data) {
$("#timecardrows_" + index + "__WOTicketRepLineNo").append('<option value="' + data.Value + '">' + data.Text + '</option>');
});
},
error: function (response) {
alert("Error : " + response);
}
});
GetCarNumber(tktid);
});
$("#timecardrows_" + index + "__WOTicketRepLineNo").change(function () {
var line = $("#timecardrows_" + index + "__WOTicketRepLineNo").val();
$("#timecardrows_" + index + "__WOTicketLaborLineNo").empty();
$.ajax({
url: "/TimeCard/GetLineDetails/",
data: { lineid: line },
cache: false,
type: "POST",
success: function (data) {
$.each(data, function (i, data) {
$("#timecardrows_" + index + "__WOTicketLaborLineNo").append('<option value="' + data.Value + '">' + data.Text + '</option>');
});
},
error: function (response) {
alert("error : " + response);
}
});
return false;
}).change();
function GetCarNumber(ticket) {
$.ajax({
url: "/TimeCard/GetCarNumber/",
data: { ticket: ticket },
cache: false,
type: "POST",
success: function (data) {
$("#timecardrows_" + index + "carNo").html(data).show();
},
error: function (response) {
alert("Error : " + response);
}
});
}
});
});
</script>
部分视图 HTML:
@using HtmlHelpers.BeginCollectionItem
@model RCRTCWA.DATA.DAL.tbl_RCRTimeCards
<div class="timecardrow">
@using (Html.BeginCollectionItem("timecardrows"))
{
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<table>
<tr>
<th class="col-sm-1">
Ticket Number
</th>
<th class="col-sm-1">
Car Number
</th>
<th class="col-sm-1">
Repair Line / Description
</th>
<th class="col-sm-1">
Labor Line / Description
</th>
<th class="col-sm-1">
Start Time
</th>
<th class="col-sm-1">
End Time
</th>
<th class="col-sm-1">
Line Complete?
</th>
</tr>
<tr>
<td class="form-group">
<div class="col-sm-1 tickets">
@Html.DropDownListFor(model => model.WOTicketNo, (SelectList)ViewData["TicketsList"], "Select one...", new { @class = "ticketddl" } )
@Html.ValidationMessageFor(model => model.WOTicketNo, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 cars">
<div id="carNo"></div>
@Html.HiddenFor(model => model.CarNo)
@Html.ValidationMessageFor(model => model.CarNo, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 replines">
@Html.DropDownListFor(model => model.WOTicketRepLineNo, new SelectList(string.Empty, "Value", "Text"), "Select one...", new { @class = "repairddl" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 laborlines">
@Html.DropDownListFor(model => model.WOTicketLaborLineNo, new SelectList(string.Empty, "Value", "Text"), "Select one...", new { @class = "lablineddl" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 starttime">
@Html.EditorFor(model => model.HRS_StartTime, new { @class = "start" })
@Html.ValidationMessageFor(model => model.HRS_StartTime, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 endtime">
@Html.EditorFor(model => model.HRS_EndTime, new { @class = "end" })
@Html.ValidationMessageFor(model => model.HRS_EndTime, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 completed">
@Html.EditorFor(model => model.Completed)
@Html.ValidationMessageFor(model => model.Completed, "", new { @class = "text-danger" })
</div>
</td>
@*<td class="form-group">
<div class="col-sm-1">
<input type="submit" value="Submit Line" class="btn btn-default" />
</div>
<div id="success" class="alert-danger">
</div>
</td>*@
</tr>
</table>
</div>
}
</div>
目前我在主视图中有脚本,并试图在用户与分部视图交互时获取分部视图控件的索引部分。我需要一个更好的方法来处理这个问题,并且需要让级联下拉列表正常工作。
我更愿意将脚本放在主视图中(如果可能)以简化操作。
您不需要使用连接的 id 字符串在下拉菜单上绑定更改事件处理程序,这很容易出错(拼写错误等)并且不容易 readable/maintainable。对于级联下拉方案,您只关心更新同一行中的第二个 select 元素。 jQuery 有一些方便的方法,如 closest
和 find
,这将使我们的生活更轻松。
为了方便以后的读者阅读,我假设您的第一个 SELECT 元素用于呈现国家列表,并且有一个 css class "countrySelect" 和第二个是 selected 国家的州并且有 css class "statesSelect" 并且两者都在同一 table 行(<tr>
).
绑定更改事件时,请确保使用 jQuery on
来执行此操作。这将为 DOM 中的 当前和未来元素启用绑定。
$("#TimeCardLines").on("change","SELECT.countrySelect",function (e) {
var _this = $(this);
var v = _this.val();
// to do :Change below url variable value as needed for your code
var urlToGetSecondDropDownData = "/Home/GetStates?countryId"+v;
$.getJSON(urlToGetSecondDropDownData,
function (res) {
var items = "";
$.each(res,
function(index, item) {
items += "<option value='" + item.Value + "'>"
+ item.Text + "</option>";
});
_this.closest("tr") // Get the same table row
.find("SELECT.statesSelect") // Find the second dropdown
.html(items); // update the content of it
});
});
假设您有一个 GetStates
操作方法,它接受 countryId 参数和 return 相应的状态作为 SelectListItem
的列表(构建第二个下拉列表所需的数据)。如下所示,
public ActionResult GetStates(int countryId)
{
var states =db.States.Where(f => f.CountryId == countryId)
.Select(f => new SelectListItem() { Value = f.Id.ToString(),
Text = f.Name})
.ToList();
return Json(states, JsonRequestBehavior.AllowGet);
}
//first dropdowlist change event
$("#countryId").change(function () {
var id = this.value;
if (id == "") {
id = "0";
}
$.get('/Home/GetStates/' + id,
function (data) {
$('#stateId').find('option').remove()
$(data).each(
function (index, item) {
$('#stateId').append('<option value="' + item.Value + '">' + item.Text + '</option>')
});
}
);
});
public ActionResult GetStates(int id)
{
List<SelectListItem> StatesList= new List<SelectListItem>();
StatesList.Add(new SelectListItem { Text = "---Select State---", Value = "0" });
var getStateCollection= (from f in _ent.States
where f.CountryId == id && f.DeletedDate == null
select new { f.Id, f.Name}).ToList();
foreach (var item in getStateCollection)
{
StatesList.Add(new SelectListItem { Text = item.Name.ToString(), Value = item.Id.ToString() });
}
return Json(StatesList, JsonRequestBehavior.AllowGet);
}
我面临的问题与这个旧问题类似 post cascading dropdown for dynamically added row。我正在使用 "BeginCollectionItemCore" NuGet 包来设置一组局部视图,因此我的控件具有唯一的 ID。问题是,我只能得到第一个局部视图来响应下拉列表的变化。随后的下拉列表不会级联。我已经尝试在部分视图和主视图中使用脚本,但两者的最终结果相同,只有第一个部分会级联。这是我的代码...
主视图 HTML:
@model IEnumerable<RCRTCWA.DATA.DAL.tbl_RCRTimeCards>
@{
ViewBag.Title = "Index";
}
<h2>Time Card</h2>
@using (Html.BeginForm())
{
<div id="TimeCardLines">
@foreach (var item in Model)
{
Html.RenderPartial("_TimeCardRow", item);
}
</div>
}
@Html.ActionLink("Add more time...", "_TimeCardRow", new { ViewContext.FormContext.FormId }, new { id = "addTime"})
主视图脚本:
<script>
$(document).ready(function () {
debugger;
$("#addTime").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#TimeCardLines").append(html); }
});
return false;
});
//var index = "";
$(".timecardrow").focusin(function () {
var ti = $(this).find("[name='timecardrows.index']");
var index = ti.val();
$("#timecardrows_" + index + "__HRS_EndTime").timepicker({
defaultTime: 'now',
minTime: '6:00am',
maxTime: '7:00pm'
});
$("#timecardrows_" + index + "__HRS_StartTime").timepicker({
defaultTime: 'now',
minTime: '6:00am',
maxTime: '7:00pm'
});
//$("#.Line_TimeCard").ajaxSuccess(function () {
// $.getJSON("/TimeCard/AddTimeCardRow/", $("#.Success").html(data).show());
//});
$("#timecardrows_" + index + "__WOTicketNo").change(function () {
var tktid = $(this).val();
$("#timecardrows_" + index + "__WOTicketRepLineNo").empty();
$.ajax({
url: "/TimeCard/GetRepairLines/",
data: { ticket: tktid },
cache: false,
type: "POST",
success: function (data) {
$.each(data, function (i, data) {
$("#timecardrows_" + index + "__WOTicketRepLineNo").append('<option value="' + data.Value + '">' + data.Text + '</option>');
});
},
error: function (response) {
alert("Error : " + response);
}
});
GetCarNumber(tktid);
});
$("#timecardrows_" + index + "__WOTicketRepLineNo").change(function () {
var line = $("#timecardrows_" + index + "__WOTicketRepLineNo").val();
$("#timecardrows_" + index + "__WOTicketLaborLineNo").empty();
$.ajax({
url: "/TimeCard/GetLineDetails/",
data: { lineid: line },
cache: false,
type: "POST",
success: function (data) {
$.each(data, function (i, data) {
$("#timecardrows_" + index + "__WOTicketLaborLineNo").append('<option value="' + data.Value + '">' + data.Text + '</option>');
});
},
error: function (response) {
alert("error : " + response);
}
});
return false;
}).change();
function GetCarNumber(ticket) {
$.ajax({
url: "/TimeCard/GetCarNumber/",
data: { ticket: ticket },
cache: false,
type: "POST",
success: function (data) {
$("#timecardrows_" + index + "carNo").html(data).show();
},
error: function (response) {
alert("Error : " + response);
}
});
}
});
});
</script>
部分视图 HTML:
@using HtmlHelpers.BeginCollectionItem
@model RCRTCWA.DATA.DAL.tbl_RCRTimeCards
<div class="timecardrow">
@using (Html.BeginCollectionItem("timecardrows"))
{
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<table>
<tr>
<th class="col-sm-1">
Ticket Number
</th>
<th class="col-sm-1">
Car Number
</th>
<th class="col-sm-1">
Repair Line / Description
</th>
<th class="col-sm-1">
Labor Line / Description
</th>
<th class="col-sm-1">
Start Time
</th>
<th class="col-sm-1">
End Time
</th>
<th class="col-sm-1">
Line Complete?
</th>
</tr>
<tr>
<td class="form-group">
<div class="col-sm-1 tickets">
@Html.DropDownListFor(model => model.WOTicketNo, (SelectList)ViewData["TicketsList"], "Select one...", new { @class = "ticketddl" } )
@Html.ValidationMessageFor(model => model.WOTicketNo, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 cars">
<div id="carNo"></div>
@Html.HiddenFor(model => model.CarNo)
@Html.ValidationMessageFor(model => model.CarNo, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 replines">
@Html.DropDownListFor(model => model.WOTicketRepLineNo, new SelectList(string.Empty, "Value", "Text"), "Select one...", new { @class = "repairddl" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 laborlines">
@Html.DropDownListFor(model => model.WOTicketLaborLineNo, new SelectList(string.Empty, "Value", "Text"), "Select one...", new { @class = "lablineddl" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 starttime">
@Html.EditorFor(model => model.HRS_StartTime, new { @class = "start" })
@Html.ValidationMessageFor(model => model.HRS_StartTime, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 endtime">
@Html.EditorFor(model => model.HRS_EndTime, new { @class = "end" })
@Html.ValidationMessageFor(model => model.HRS_EndTime, "", new { @class = "text-danger" })
</div>
</td>
<td class="form-group">
<div class="col-sm-1 completed">
@Html.EditorFor(model => model.Completed)
@Html.ValidationMessageFor(model => model.Completed, "", new { @class = "text-danger" })
</div>
</td>
@*<td class="form-group">
<div class="col-sm-1">
<input type="submit" value="Submit Line" class="btn btn-default" />
</div>
<div id="success" class="alert-danger">
</div>
</td>*@
</tr>
</table>
</div>
}
</div>
目前我在主视图中有脚本,并试图在用户与分部视图交互时获取分部视图控件的索引部分。我需要一个更好的方法来处理这个问题,并且需要让级联下拉列表正常工作。
我更愿意将脚本放在主视图中(如果可能)以简化操作。
您不需要使用连接的 id 字符串在下拉菜单上绑定更改事件处理程序,这很容易出错(拼写错误等)并且不容易 readable/maintainable。对于级联下拉方案,您只关心更新同一行中的第二个 select 元素。 jQuery 有一些方便的方法,如 closest
和 find
,这将使我们的生活更轻松。
为了方便以后的读者阅读,我假设您的第一个 SELECT 元素用于呈现国家列表,并且有一个 css class "countrySelect" 和第二个是 selected 国家的州并且有 css class "statesSelect" 并且两者都在同一 table 行(<tr>
).
绑定更改事件时,请确保使用 jQuery on
来执行此操作。这将为 DOM 中的 当前和未来元素启用绑定。
$("#TimeCardLines").on("change","SELECT.countrySelect",function (e) {
var _this = $(this);
var v = _this.val();
// to do :Change below url variable value as needed for your code
var urlToGetSecondDropDownData = "/Home/GetStates?countryId"+v;
$.getJSON(urlToGetSecondDropDownData,
function (res) {
var items = "";
$.each(res,
function(index, item) {
items += "<option value='" + item.Value + "'>"
+ item.Text + "</option>";
});
_this.closest("tr") // Get the same table row
.find("SELECT.statesSelect") // Find the second dropdown
.html(items); // update the content of it
});
});
假设您有一个 GetStates
操作方法,它接受 countryId 参数和 return 相应的状态作为 SelectListItem
的列表(构建第二个下拉列表所需的数据)。如下所示,
public ActionResult GetStates(int countryId)
{
var states =db.States.Where(f => f.CountryId == countryId)
.Select(f => new SelectListItem() { Value = f.Id.ToString(),
Text = f.Name})
.ToList();
return Json(states, JsonRequestBehavior.AllowGet);
}
//first dropdowlist change event
$("#countryId").change(function () {
var id = this.value;
if (id == "") {
id = "0";
}
$.get('/Home/GetStates/' + id,
function (data) {
$('#stateId').find('option').remove()
$(data).each(
function (index, item) {
$('#stateId').append('<option value="' + item.Value + '">' + item.Text + '</option>')
});
}
);
});
public ActionResult GetStates(int id)
{
List<SelectListItem> StatesList= new List<SelectListItem>();
StatesList.Add(new SelectListItem { Text = "---Select State---", Value = "0" });
var getStateCollection= (from f in _ent.States
where f.CountryId == id && f.DeletedDate == null
select new { f.Id, f.Name}).ToList();
foreach (var item in getStateCollection)
{
StatesList.Add(new SelectListItem { Text = item.Name.ToString(), Value = item.Id.ToString() });
}
return Json(StatesList, JsonRequestBehavior.AllowGet);
}