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 有一些方便的方法,如 closestfind,这将使我们的生活更轻松。

为了方便以后的读者阅读,我假设您的第一个 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);
    }