在EditorFor MVC C#视图上选中全部复选框

时间:2018-09-07 19:50:30

标签: javascript c# jquery razor asp.net-mvc-5

我当前的视图显示的是员工列表。显示的所有行和列均受模型限制。

请参见下面的查看代码:

@using System.Linq
@using DN_.Extensions
@model DN_.Models.NotificationsModel
<script src="~/Scripts/jquery-3.3.1.min.js"></script>

<script type="text/javascript" language="javascript">
    $(function () {
        $("#checkAll").click(function () {
            $("input[id='cb_Notify']").prop("checked", this.checked).change();
            var count = $("input[name='cb_Notify']:checked").length;
        })

        $("input[id='cb_Notify']").click(function () {
            if ($("input[name='cb_Notify']:checked").length == $("input[id='cb_Notify']").length) {
                $("#checkAll").prop("checked", "checked").change();
            }
            else {
                $("#checkAll").removeProp("checked").change();
            }
        })
    })
</script>

@{
    ViewBag.Title = "Link Employees";
}

<h2>Link Employees</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <input id="btn_Save" type="submit" value="Save" class="btn btn-default" />

    @Html.ActionLink("Back to List", "Index")
    <p>
        Select All <input type="checkbox" id="checkAll" />
        Select All On Premise <input type="checkbox" id="checkAllOnPremise" />
        Select All Full Timers<input type="checkbox" id="checkAllFullTimers" />
    </p>
    <table class="table">
        <tr>
            <th align=center>Notify?</th>
            <th align=center>Employee Name</th>
            <th align=center>Is On Premise</th>
            <th align=center>Is Full Time</th>
            <th align=center>Notified On</th>
        </tr>

        @for (var i = 0; i < Model.EmployeeNotification.Count; i++)
        {

            <tr>
                <td>
                    @*Do not allow editing of the Notify field for employees who have been sent the notification already*@
                    @if (Model.EmployeeNotification[i].NotifiedOn >= DateTime.Parse("2000-01-01 12:00:00 AM"))
                    {
                        @Html.DisplayFor(modelItem => Model.EmployeeNotification[i].Notify)
                    }
                    else
                    {
                        @*Hidden items for the post back information*@
                        @Html.HiddenFor(modelItem => Model.EmployeeNotification[i].NotificationID)
                        @Html.HiddenFor(modelItem => Model.EmployeeNotification[i].EmployeeID)
                        @Html.HiddenFor(modelItem => Model.EmployeeNotification[i].EmployeeName)

                        @*BELOW 3 LINES ARE THE PROBLEM DESCRIBED*@
                        @Html.EditorFor(modelItem => Model.EmployeeNotification[i].Notify)
                        @Html.CheckBoxFor(modelItem => Model.EmployeeNotification[i].Notify)
                        @*This checkbox below works with the "Select All" option, but data is not posted back.*@
                        @Html.CheckBox("cb_Notify", Model.EmployeeNotification[i].Notify)
                    }
                </td>
                <td>
                    @Model.EmployeeNotification[i].EmployeeName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.EmployeeNotification[i].IsOnPremise)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.EmployeeNotification[i].IsFullTime)
                </td>
                <td>
                    @if (Model.EmployeeNotification[i].NotifiedOn >= DateTime.Parse("2000-01-01 12:00:00 AM"))
                    {
                        @Html.RenderDate(Model.EmployeeNotification[i].NotifiedOn, "dd MMM yyyy")
                    }
                </td>
            </tr>
        }
    </table>
}

我的问题如下: 我可以使用第一条“通知复选框”代码行(即使用EditorFor和CheckBoxFor选项)手动选择所有“通知”复选框,并将数据保存在回发事件中。 如何获取全选复选框选项以在EditorFor或CheckBoxFor模型绑定复选框上使用。

对我来说,命名的CheckBox选项可以与“全选”框一起使用,但是我无法将数据返回到事件处理程序中。所选“通知”列的模型数据返回为空。

我假定的主要问题是,如果我在调试时查看生成的名称和id元素代码(示例输出源代码数据并添加了一些注释),则自动化为复选框的元素命名的方式:

<td>
    <!--Required, hidden data for post back event handler:-->
    <input name="EmployeeNotification[3].NotificationID" id="EmployeeNotification_3__NotificationID" type="hidden" value="6" data-val-number="The field NotificationID must be a number." data-val="true">
    <input name="EmployeeNotification[3].EmployeeID" id="EmployeeNotification_3__EmployeeID" type="hidden" value="27" data-val-number="The field EmployeeID must be a number." data-val="true">
    <input name="EmployeeNotification[3].EmployeeName" id="EmployeeNotification_3__EmployeeName" type="hidden" value="Charlie">
    <!--@Html.EditorFor element-->
    <input name="EmployeeNotification[3].Notify" id="EmployeeNotification_3__Notify" type="checkbox" value="true" data-val="true" data-val-required="The Notify field is required.">
    <input name="EmployeeNotification[3].Notify" type="hidden" value="false">
    <!--@Html.CheckBoxFor element-->
    <input name="EmployeeNotification[3].Notify" id="EmployeeNotification_3__Notify" type="checkbox" value="true">
    <input name="EmployeeNotification[3].Notify" type="hidden" value="false">
    <!--@Html.CheckBox element-->
    <input name="cb_Notify" id="cb_Notify" type="checkbox" value="true">
    <input name="cb_Notify" type="hidden" value="false">
</td>

所以我要么需要获得“全选”复选框才能与@ Html.EditorFor或@ Html.CheckBoxFor选项一起使用,否则我需要在事件处理程序中获取@ Html.CheckBox中设置的值。

我无法在“选择”或“全部选中”复选框的其他类似问题中获得所需的答案,因为它们似乎使用其他编码语言。请帮忙。

请注意:

只需将显而易见的内容放在那里:目的是最后只保留可选的Notify复选框中的1个。一个会工作的。不是全部三个。由于测试和调试失败,我暂时只显示它们。

2 个答案:

答案 0 :(得分:2)

由于您的name(和id)属性包括集合索引器,因此您可以使用jQuery Attribute Ends With Selector(例如$('input[type="checkbox"][name$="Notify"]')),但这会更容易使用复选框的类名。

@Html.CheckBoxFor(m => m.EmployeeNotification[i].Notify, new { @class = "notify" })

然后您的脚本就可以了

// cache for performance
var checkboxes = $('.notify');
var total = checkboxes.length;
var checkall = $('#checkAll');

checkall.change(function() {
    checkboxes.prop('checked', $(this).is(':checked'));
})

checkboxes.change(function() {
    var count = checkboxes.filter(':checked').length;
  checkall.prop('checked', (count == total));
})

但是,您的代码还有另一个问题。默认情况下,DefaultModelBinder要求集合索引器从零开始且连续。如果集合中的第一项满足@if (Model.EmployeeNotification[i].NotifiedOn >= DateTime.Parse("2000-01-01 12:00:00 AM"))条件,则POST方法中的EmployeeNotification属性将为null。或者,如果说第三个项目满足该条件,那么EmployeeNotification将仅包含前两个记录。您需要为集合索引器添加一个附加输入,以允许DefaultModelBinder绑定非零/非连续索引器

@if (Model.EmployeeNotification[i].NotifiedOn >= DateTime.Parse("2000-01-01 12:00:00 AM"))
{
    @Html.DisplayFor(m => m.EmployeeNotification[i].Notify)
}
else
{
    @Html.HiddenFor(m => m.EmployeeNotification[i].NotificationID)
    @Html.HiddenFor(m => m.EmployeeNotification[i].EmployeeID)
    @Html.HiddenFor(m => m.EmployeeNotification[i].EmployeeName)
    @Html.CheckBoxFor(m => m.EmployeeNotification[i].Notify, new { @class = "notify" })
    <input type="hidden" name="EmployeeNotification.Index" value="@i" /> // add this
}

此外,我建议您删除其他隐藏的输入,除了ID身份(我假设是NotificationID)之外。它只是包含不必要的html,因为保存数据不需要这些属性,它只是允许恶意用户更改这些值。我还建议您的视图模型包含一个(例如)bool IsEditable属性,并且在将数据模型映射到视图模型时,应根据GET方法中的条件设置该值,以便使用if块变成@if (Model.EmployeeNotification[i].IsEditable) { ... } else { ... }

答案 1 :(得分:0)

我也从斯蒂芬的建议中找到了灵感,从而找到了上述斯蒂芬帖子的另一种解决方案。不是很干净,但是,它可以工作。我绝对推荐斯蒂芬的代码。简洁明了。

  1. 将自定义cb_Notify复选框移动并隐藏到单元格的顶部,以便每行创建它。这将使其在所有行中都可搜索,等等,我可以在循环中使用它:

    @Html.CheckBox("cb_Notify", Model.EmployeeNotification[i].Notify, new { type = "hidden" })
    @*Do not allow editing of the Notify field for employees who have been sent the notification already*@
    @if (Model.EmployeeNotification[i].NotifiedOn >= DateTime.Parse("2000-01-01 12:00:00 AM"))
    {
        @Html.DisplayFor(modelItem => Model.EmployeeNotification[i].Notify)
    }
    else
    {
        @*Hidden items for the post back information*@
        @Html.HiddenFor(modelItem => Model.EmployeeNotification[i].NotificationID)
        @Html.HiddenFor(modelItem => Model.EmployeeNotification[i].EmployeeID)
        @Html.CheckBoxFor(modelItem => Model.EmployeeNotification[i].Notify, new { @class = "notify" })
    }
    
  2. 然后对于jquery,使用隐藏的复选框循环遍历所有行并设置需要设置的值:

    // cache for performance
    var checkAll = $('#checkAll');
    
    checkAll.click(function () {
        var maxCount = $("input[id='cb_Notify']").length;
        var loopCounter;
        var customer;
        for (loopCounter = 0; loopCounter < maxCount; loopCounter++) {
            customer = $("input[name='EmployeeNotification[" + loopCounter + "].EmployeeName']").val();
            if (customer != null) {
                $("input[name='EmployeeNotification[" + loopCounter + "].Notify']").prop("checked", this.checked);
            }
        }
        toggleSetAllCheckBoxStates();
    })
    

我创建的toggleSetAllCheckBoxStates()函数是由于存在第二个要求(超出此问题的范围,因此我将其保留),以便仅根据其数据设置选择Employee数据的子集。但这与上述示例相同。

这样,在回发事件中,我过滤掉了空数据,因为已发送通知的空数据将不包含EmployeeID。其余数据已成功保存。