65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 5 中的基于 AJAX 的 CRUD 操作的 Grid View

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (8投票s)

2017年6月14日

CPOL

11分钟阅读

viewsIcon

50531

downloadIcon

3872

在这篇文章中,我将解决这个问题,我们将学习如何在不刷新整个页面的情况下,使用 JQuery DataTables 在一页中实现 CRUD 操作。

引言

我经常在 **StackOverflow** 等在线论坛上看到这样的问题,提问者能够为他们的实体创建 CRUD 操作,这是一种正常的表单提交,但他们在通过 ajax 实现 CRUD 以便页面不完全刷新以获得更好的用户体验时会遇到困难。

在这篇文章中,我将解决这个问题,我们将学习如何在不刷新整个页面的情况下,使用 **JQuery DataTables** 在一页中实现 CRUD 操作。

背景

在之前的几篇文章中,我一直写到 **JQuery DataTables** 的用法,它可以被用来在 asp.net mvc 中构建类似 **GridView** 的功能,我们看到了如何使用 **NuGet 包管理器** 安装它并使用该插件实现一个简单的网格,该插件为我们提供了排序、搜索和分页等基本功能,然后我们看到了如何实现分页、过滤和排序,然后我们继续查看如何添加高级搜索以获得更好的用户体验。

如果有人想复习或有兴趣阅读相关的先前文章,可以在这里找到它们:

在这篇文章中,我们将学习如何为我们已经使用 JQuery DataTables 实现的网格添加创建、更新和删除操作支持。最终结果将看起来像这样

使用脚本创建数据库

首先,我们将运行脚本来创建数据库和表,这将是本文的关键。以下是脚本:

CREATE DATABASE [AdvancedSearchGridExampleMVC]
GO
CREATE TABLE [dbo].[FacilitySites] ([FacilitySiteID] UNIQUEIDENTIFIER NOT NULL,
                                    [FacilityName]   NVARCHAR (MAX)   NULL,
                                    [IsActive]       BIT              NOT NULL,
                                    [CreatedBy]      UNIQUEIDENTIFIER NOT NULL,
                                    [CreatedAt]      DATETIME         NOT NULL,
                                    [ModifiedBy]     UNIQUEIDENTIFIER NULL,
                                    [ModifiedAt]     DATETIME         NULL,
                                    [IsDeleted]      BIT              NOT NULL
                                   );
GO

CREATE TABLE [dbo].[Assets] (
                             [AssetID]                   UNIQUEIDENTIFIER NOT NULL,
                             [Barcode]                   NVARCHAR (MAX)   NULL,
                             [SerialNumber]              NVARCHAR (MAX)   NULL,
                             [PMGuide]                   NVARCHAR (MAX)   NULL,
                             [AstID]                     NVARCHAR (MAX)   NOT NULL,
                             [ChildAsset]                NVARCHAR (MAX)   NULL,
                             [GeneralAssetDescription]   NVARCHAR (MAX)   NULL,
                             [SecondaryAssetDescription] NVARCHAR (MAX)   NULL,
                             [Quantity]                  INT              NOT NULL,
                             [Manufacturer]              NVARCHAR (MAX)   NULL,
                             [ModelNumber]               NVARCHAR (MAX)   NULL,
                             [Building]                  NVARCHAR (MAX)   NULL,
                             [Floor]                     NVARCHAR (MAX)   NULL,
                             [Corridor]                  NVARCHAR (MAX)   NULL,
                             [RoomNo]                    NVARCHAR (MAX)   NULL,
                             [MERNo]                     NVARCHAR (MAX)   NULL,
                             [EquipSystem]               NVARCHAR (MAX)   NULL,
                             [Comments]                  NVARCHAR (MAX)   NULL,
                             [Issued]                    BIT              NOT NULL,
                             [FacilitySiteID]            UNIQUEIDENTIFIER NOT NULL
                            );

GO

CREATE NONCLUSTERED INDEX [IX_FacilitySiteID]
   ON [dbo].[Assets]([FacilitySiteID] ASC);

GO
ALTER TABLE [dbo].[Assets]
    ADD CONSTRAINT [PK_dbo.Assets] PRIMARY KEY CLUSTERED ([AssetID] ASC);

GO

ALTER TABLE [dbo].[Assets]
   ADD CONSTRAINT [FK_dbo.Assets_dbo.FacilitySites_FacilitySiteID] FOREIGN KEY ([FacilitySiteID]) _
REFERENCES [dbo].[FacilitySites] ([FacilitySiteID]) ON DELETE CASCADE;

GO

您可以在附件的源代码中找到名为 dbScript.sql 的文件,其中还包含用于快速入门的示例数据。运行它将创建数据库并在表中添加一些示例数据。

创建/插入操作

对于插入部分,首先我们需要在 Views >> Asset 中创建一个局部视图。右键单击 Asset 文件夹,然后导航到 Add >> MVC 5 Partial Page (Razor),如下图所示:

打开渲染 Asset 行的容器视图 _AssetsPartial.cshtml,该文件位于 Views >> Asset 目录中。添加用于“添加 Asset”按钮的 HTML,该按钮将打开一个弹出窗口,用于在数据库中插入新的 Asset 行。

<button type="button" class="btn btn-default btn-md" data-toggle="modal" data-url="@Url.Action("Create","Asset")" id="btnCreateAsset">
  <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> Add Asset
</button>

现在,打开 Asset 的 Index 视图,即 Views >> Asset >> index.csthtml。在脚本部分,为我们刚刚创建的按钮单击事件添加以下 jQuery 代码。它将调用 create get 操作,并将 Asset 的局部视图显示在 bootstrap modal 中供用户使用。代码如下:

$("#btnCreateAsset").on("click", function () {

       var url = $(this).data("url");

       $.get(url, function (data) {
               $('#createAssetContainer').html(data);

               $('#createAssetModal').modal('show');
       });

});

我们还需要添加一个带有容器 div 的 bootstrap modal,我们将在其中加载 Asset 的 create 局部视图。因此,我们将以下 HTML 添加到 Index.cshtml 视图的末尾:

<div class="modal fade" id="createAssetModal" tabindex="-1" role="dialog" aria-labelledby="CreateAssetModal" aria-hidden="true" data-backdrop="static">
    <div id="createAssetContainer">
    </div>
</div>

实现 Add GET 操作

在 Asset 控制器文件(位于 Controllers >> AssetController.cs)中,为 Asset 创建的 GET 请求添加 Action 方法。上面的 jQuery 代码将调用此方法。在 Action 方法内部,我们填充 ViewModel 并将实例传回 PartialView,就像我们在 mvc 应用程序中通常做的那样。

public ActionResult Create()
{
    var model = new AssetViewModel();
    model.FacilitySitesSelectList = GetFacilitiySitesSelectList();
    return View("_CreatePartial", model);
}

添加局部视图创建

在项目中的 Asset Views 中添加一个新的局部视图用于创建表单。为此,请在 Solution Explorer 中右键单击 Views 下的 Asset 文件夹。

在文本框中输入局部视图的名称,例如 _CreatePartial,或者您认为更适合您的名称。

实现 Add 局部视图

现在我们将编写上一步中创建的局部视图 _CreatePatial。在此视图中添加以下代码:

@model GridAjaxCRUDMVC.Models.AssetViewModel
@{
    Layout = null;
}

<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title">Add Asset</h4>
        </div>
        @using (Ajax.BeginForm("Create", "Asset", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "CreateAssetSuccess" }, new {  @class = "form-horizontal", role = "form" }))
        {
            <div class="modal-body">
                <div class="form-horizontal">
                    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                    @Html.HiddenFor(model => model.AssetID, new { Value = Guid.NewGuid() })
                    <div class="form-group">
                        @Html.LabelFor(model => model.Barcode, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Barcode, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Barcode, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.SerialNumber, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.SerialNumber, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.SerialNumber, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.FacilitySiteID, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.DropDownListFor(model => model.FacilitySiteID, Model.FacilitySitesSelectList, "Select One", new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.FacilitySiteID, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.PMGuide, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.PMGuide, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.PMGuide, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.AstID, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.AstID, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.AstID, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.ChildAsset, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.ChildAsset, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.ChildAsset, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.GeneralAssetDescription, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.GeneralAssetDescription, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.GeneralAssetDescription, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.SecondaryAssetDescription, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.SecondaryAssetDescription, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.SecondaryAssetDescription, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Manufacturer, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Manufacturer, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Manufacturer, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.ModelNumber, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.ModelNumber, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.ModelNumber, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Building, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Building, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Building, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Floor, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Floor, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Floor, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Corridor, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Corridor, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Corridor, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.RoomNo, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.RoomNo, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.RoomNo, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.MERNo, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.MERNo, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.MERNo, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.EquipSystem, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.EquipSystem, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.EquipSystem, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Comments, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Comments, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Comments, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Issued, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            <div class="checkbox">
                                @Html.EditorFor(model => model.Issued)
                                @Html.ValidationMessageFor(model => model.Issued, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>


                </div>
            </div>
            <div class="modal-footer">
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                        <input type="submit" class="btn btn-primary" value="Save" />
                    </div>
                </div>
            </div>
        }
    </div>
</div>

实现 Add/Create POST 操作

在视图代码中需要注意的重要部分是 Ajax.BeginForm 辅助部分,因为类名 Ajax 应该足以表明它将通过 Ajax 将模型发布回控制器操作,这意味着整个过程不会刷新,即在 asp.net web forms 方面不会发生完全的回发。

post 操作只是将 ViewModel 对象映射到 Model,然后将其保存在存储库中。

[HttpPost]
public async Task<ActionResult> Create(AssetViewModel assetVM)
{
   if (!ModelState.IsValid)
        return View("_CreatePartial", assetVM);

   Asset asset = MaptoModel(assetVM);

   DbContext.Assets.Add(asset);
   var task = DbContext.SaveChangesAsync();
   await task;

   if (task.Exception != null)
   {
       ModelState.AddModelError("", "Unable to add the Asset");
       return View("_CreatePartial", assetVM);
   }

   return Content("success");
}

我们正在尝试将新输入的 Asset 保存到数据库并跟踪其是否成功保存。如果成功保存,我们将返回一个字符串消息 **success** 给客户端。在 Ajax Form 的成功回调中,我们将检查操作是否成功,以便根据结果进行 UI 更改。

实现 Ajax 回调函数

我们可以看到在 BeginForm 辅助方法的参数中,我们指定了当 Ajax Form 成功从服务器返回时要调用的 JavaScript 函数,即 OnSuccess = <span style="color: #990000">"CreateAssetSuccess"</span>

现在让我们转到 Asset 的 index.cshtml 视图并定义成功回调实现:

function CreateAssetSuccess(data) {

    if (data != "success") {
       $('#createAssetContainer').html(data);
        return;
    }
    $('#createAssetModal').modal('hide');
    $('#createAssetContainer').html("");
    assetListVM.refresh();

}

在这里,如果操作不成功,我们将更新客户端 HTML 以通知用户创建失败;如果插入成功,我们将关闭模态弹出窗口并刷新网格以显示最新信息。

编辑/更新操作

到目前为止,我们应该能够运行该应用程序并通过上面创建的 bootstrap modal 成功地通过 Ajax 将新的 Asset 添加到数据库中。现在让我们继续进行 Asset 的更新部分。

我们将数据表列集合中添加另一列,其中包含一个超链接,该链接将导航到 Edit 视图。但是,由于我们正在使用 Ajax 和 bootstrap modal,我们将以同样的方式进行更新,因此不会涉及重定向。让我们开始吧。

打开 Index.csthml 文件,并在 jQuery datatable 初始化中的列集合中添加一个新列。更新列数组后,我们的代码将如下所示:

"columns": [
              { "title": "Bar Code", "data": "BarCode", "searchable": true },
              { "title": "Manufacturer", "data": "Manufacturer", "searchable": true },
              { "title": "Model", "data": "ModelNumber", "searchable": true },
              { "title": "Building", "data": "Building", "searchable": true },
              { "title": "Room No", "data": "RoomNo" },
              { "title": "Quantity", "data": "Quantity" },
              {
                  "title": "Actions",
                  "data": "AssetID",
                  "searchable": false,
                  "sortable": false,
                  "render": function (data, type, full, meta) {
                      return '<a href="@Url.Action("Edit","Asset")?id=' + data + '" class="editAsset">Edit</a>';
                     }
              }
           ]

我们将新列的标题设置为显示 Actions 作为标题,并且我们将需要禁用该列的搜索和排序,因为它用于编辑操作,因此在此列上启用排序和搜索没有意义。接下来,我们定义列的渲染方法,并生成锚链接 HTML,该 HTML 可以调用 Asset 控制器的 Edit 操作,并将当前 Asset ID 传递过去以提取其信息并在 Edit 视图中显示。

定义 Edit/Update GET 操作

在进行 datatable js 更改后,现在我们需要创建一个 get action 方法,该方法将从数据库中检索 Asset 记录并将其显示给用户进行编辑,以弹出窗口的形式。

让我们实现它的 Edit get 操作:

public ActionResult Edit(Guid id)
{
    var asset = DbContext.Assets.FirstOrDefault(x => x.AssetID == id);

    AssetViewModel assetViewModel = MapToViewModel(asset);

    if (Request.IsAjaxRequest())
        return PartialView("_EditPartial",assetViewModel);

    return View(assetViewModel);
}

该操作只是从数据库中检索行,在将其转换为 ViewModel 后,将其传回 partial view 进行渲染,或返回给客户端进行处理。由于不会发生回发,它将生成 HTML 并将 HTML 作为 ajax 调用的响应发送回来,客户端将处理该 HTML 并决定将其放在何处。

使用 JQuery 在客户端处理 Action 链接事件

从列渲染函数中,您可以看到锚链接上应用了一个名为 EditAsset 的类。这是因为 jQuery 事件处理程序将应用于锚链接,并且 Ajax 调用将发送到服务器。让我们在 Index 视图中定义该链接的事件处理程序:

$('#assets-data-table').on("click", ".editAsset", function (event) {

        event.preventDefault();

        var url = $(this).attr("href");

        $.get(url, function (data) {
            $('#editAssetContainer').html(data);

            $('#editAssetModal').modal('show');
        });

 });

添加 Bootstrap Modal

现在将 bootstrap modal HTML 添加到 Index 视图中,该视图将作为加载 Edit 视图的占位符。将其定义在创建 bootstrap modal HTML 之后:

<div class="modal fade" id="editAssetModal" tabindex="-1" role="dialog" aria-labelledby="EditAssetModal" aria-hidden="true" data-backdrop="static">
    <div id="editAssetContainer">
    </div>
</div>

Edit/Update 局部视图创建

按照我们为添加 _CreatePartial.cshtml 所做的相同步骤,创建另一个新的局部视图,该视图用于创建 Asset。因此,在 Views 下的 Asset 文件夹中添加一个名为 _EditPartial.cshtml 的新局部视图,并在其中添加以下代码:

@model TA_UM.ViewModels.AssetViewModel
    @{ 
        Layout = null;
    }
<div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                <h4 class="modal-title">Edit Asset</h4>
            </div>
@using (Ajax.BeginForm("Edit", "Asset", null, new AjaxOptions { HttpMethod="Post", OnSuccess = "UpdateAssetSuccess" }, new { @class = "form-horizontal", role = "form" }))
            {
                <div class="modal-body">
                    <div class="form-horizontal">
                        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                        @Html.HiddenFor(model => model.AssetID)

                        <div class="form-group">
                            @Html.LabelFor(model => model.Barcode, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Barcode, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Barcode, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.SerialNumber, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.SerialNumber, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.SerialNumber, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.FacilitySiteID, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.DropDownListFor(model => model.FacilitySiteID,Model.FacilitySitesSelectList, "Select One", new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.FacilitySiteID, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.PMGuide, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.PMGuide, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.PMGuide, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.AstID, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.AstID, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.AstID, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.ChildAsset, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.ChildAsset, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.ChildAsset, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.GeneralAssetDescription, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.GeneralAssetDescription, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.GeneralAssetDescription, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.SecondaryAssetDescription, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.SecondaryAssetDescription, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.SecondaryAssetDescription, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.Manufacturer, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Manufacturer, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Manufacturer, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.ModelNumber, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.ModelNumber, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.ModelNumber, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.Building, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Building, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Building, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.Floor, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Floor, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Floor, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.Corridor, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Corridor, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Corridor, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.RoomNo, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.RoomNo, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.RoomNo, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.MERNo, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.MERNo, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.MERNo, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.EquipSystem, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.EquipSystem, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.EquipSystem, "", new { @class = "text-danger" })
                            </div>
                        </div>
<div class="form-group">
                            @Html.LabelFor(model => model.Comments, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                @Html.EditorFor(model => model.Comments, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Comments, "", new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(model => model.Issued, htmlAttributes: new { @class = "control-label col-md-2" })
                            <div class="col-md-10">
                                <div class="checkbox">
                                    @Html.EditorFor(model => model.Issued)
                                    @Html.ValidationMessageFor(model => model.Issued, "", new { @class = "text-danger" })
                                </div>
                            </div>
                        </div>


                    </div>
                </div>
<div class="modal-footer">
                        <div class="form-group">
                            <div class="col-md-offset-2 col-md-10">
                                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                                <input type="submit" class="btn btn-primary" value="Save changes"/>
                            </div>
                        </div>
                    </div>
            }
        </div>
    </div>

Edit 视图与 Insert 视图非常相似,除了它将发布到不同的操作,该操作将负责处理特定 Asset 行的更新。

实现 Edit/Update POST 操作

现在让我们实现 Edit 的 post 操作:

        [HttpPost]
        public async Task<ActionResult> Edit(AssetViewModel assetVM)
        {

            assetVM.FacilitySitesSelectList = GetFacilitiySitesSelectList(assetVM.FacilitySiteID);
            if (!ModelState.IsValid)
            {
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                return View(Request.IsAjaxRequest() ? "_EditPartial" : "Edit", assetVM);
            }

            Asset asset = MaptoModel(assetVM);

            DbContext.Assets.Attach(asset);
            DbContext.Entry(asset).State = EntityState.Modified;
            var task = DbContext.SaveChangesAsync();
            await task;

            if (task.Exception != null)
            {
                ModelState.AddModelError("", "Unable to update the Asset");
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                return View(Request.IsAjaxRequest() ? "_EditPartial" : "Edit", assetVM);
            }

            if(Request.IsAjaxRequest())
            {
                return Content("success");
            }

            return RedirectToAction("Index");

        }

处理 Update Ajax 成功回调

Index.cshtml 中,实现 OnSuccess 回调函数,该函数将在 Asset 更新成功后调用。在回调函数中,模态窗口将被关闭,表单将被清除,以便如果用户再次打开进行编辑,将获取新的 HTML 并将更新后的信息显示在视图中。当然,datatable 也将被刷新以显示最新的更新:

        /**** Edit Asset Ajax Form CallBack ********/

        function UpdateAssetSuccess(data) {

            if (data != "success") {
                $('#editAssetContainer').html(data);
                return;
            }
            $('#editAssetModal').modal('hide');
            $('#editAssetContainer').html("");
            assetListVM.refresh();

        }

对于 details 和 delete 操作,将遵循相同的方法。让我们看看 delete 部分。首先,打开 Index 视图,让我们在上面定义编辑链接的渲染函数中添加 details 和 delete 操作的超链接:

"render": function (data, type, full, meta) {
             return '<a href="@Url.Action("Edit","Asset")?id=' + data + '" class="editAsset">Edit</a> | <a href="@Url.Action("Details","Asset")?id=' + data + '">Details</a> | <a href="@Url.Action("Delete","Asset")?id=' + data + '">Delete</a>';
          }

现在 Action 列将包含 Edit、Details 和 Delete Asset 的三个超链接。

检索和删除操作

在这一点上,我们应该能够看到插入和更新功能正常工作。现在我们将转向删除部分,看看如何实现 Assets 的删除。为此,我们需要向我们在列中生成的超链接添加类,这些列将出现链接。让我们先做这个。我们需要在 DataTables 初始化代码的 columns 数组的最后一个列中定义 render 属性,并且我们将定义列值的渲染方式:

"render": function (data, type, full, meta) {
            return '<a href="@Url.Action("Edit","Asset")?id=' + data + '" class="editAsset">Edit</a> | <a href="@Url.Action("Details","Asset")?id=' + data + '" class="detailsAsset">Details</a> | <a href="@Url.Action("Delete","Asset")?id=' + data + '" class="deleteAsset">Delete</a>';
          }

我们已将 detailsAsset deleteAsset 类添加到相应的锚标签,以便我们可以使用 jQuery 绑定事件并执行一些逻辑来显示详情或删除特定 Asset。

完成上述步骤后,现在我们将编写事件来处理这两个超链接的单击事件。我们将需要编写以下代码来实现此目的:

$('#assets-data-table').on("click", ".detailsAsset", function (event) {

                event.preventDefault();

                var url = $(this).attr("href");

                $.get(url, function (data) {
                    $('#detailsAssetContainer').html(data);

                    $('#detailsAssetModal').modal('show');
                });

现在,由于 details 标签的 handler 已经就位,让我们转到视图部分并编写相应视图中所需的 razor 代码。因此,创建一个名为 _detailsPartial 的新局部视图,该视图将负责显示所选 Asset 的详细信息。为此,再次右键单击 Solution Explorer 中 Views 目录下的 Asset 文件夹,并执行与之前相同的步骤,然后以提到的名称创建局部视图,并在其中添加以下代码:

@model GridAdvancedSearchMVC.Models.AssetViewModel

<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title">Asset Details</h4>
            <hr/>
        </div>

        <div class="modal-body">
            <dl class="dl-horizontal">
                <dt>
                    @Html.DisplayNameFor(model => model.Barcode)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Barcode)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.SerialNumber)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.SerialNumber)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.FacilitySite)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.FacilitySite)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.PMGuide)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.PMGuide)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.AstID)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.AstID)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.ChildAsset)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.ChildAsset)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.GeneralAssetDescription)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.GeneralAssetDescription)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.SecondaryAssetDescription)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.SecondaryAssetDescription)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Quantity)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Quantity)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Manufacturer)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Manufacturer)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.ModelNumber)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.ModelNumber)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Building)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Building)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Floor)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Floor)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Corridor)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Corridor)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.RoomNo)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.RoomNo)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.MERNo)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.MERNo)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.EquipSystem)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.EquipSystem)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Comments)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Comments)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Issued)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Issued)
                </dd>

            </dl>

        </div>

    </div>
</div>

Details GET 操作实现

现在是时候定义控制器操作代码了,该代码将从数据源检索 Asset 信息并将其传递回视图供用户显示。这是控制器操作的代码:

        public async Task<ActionResult> Details(Guid id)
        {
            var asset = await DbContext.Assets.FirstOrDefaultAsync(x => x.AssetID == id);
            var assetVM = MapToViewModel(asset);

            if(Request.IsAjaxRequest())
                return PartialView("_detailsPartial", assetVM);

            return View(assetVM);
        }

实现 Delete 操作

我们将添加 delete 的 GET action 方法,该方法将从存储库中获取特定的 Asset 并将其详细信息显示在弹出窗口中,用户可以在其中删除或取消。以下是 action 方法的代码:

        public ActionResult Delete(Guid id)
        {
            var asset = DbContext.Assets.FirstOrDefault(x => x.AssetID == id);

            AssetViewModel assetViewModel = MapToViewModel(asset);

            if (Request.IsAjaxRequest())
                return PartialView("_DeletePartial", assetViewModel);
            return View(assetViewModel);
        }

Delete 局部视图添加

我们现在将在解决方案中为 delete 部分添加另一个局部视图。因此,导航到 Solution Explorer 中的 Views >> Asset 文件夹,然后从右键单击 Asset 文件夹时出现的上下文菜单中,使用 Add >> MVC 5 Partial Page (Razor) 选项添加一个新视图,并将局部视图命名为 _DeletePartial,并在其中添加以下代码:

@model GridAdvancedSearchMVC.Models.AssetViewModel


<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title">Delete Asset</h4>
            <h3>Are you sure you want to delete this?</h3>

        </div>

        <div class="modal-body">
            <dl class="dl-horizontal">
                <dt>
                    @Html.DisplayNameFor(model => model.Barcode)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Barcode)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.SerialNumber)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.SerialNumber)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.FacilitySite)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.FacilitySite)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.PMGuide)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.PMGuide)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.AstID)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.AstID)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.ChildAsset)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.ChildAsset)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.GeneralAssetDescription)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.GeneralAssetDescription)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.SecondaryAssetDescription)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.SecondaryAssetDescription)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Quantity)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Quantity)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Manufacturer)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Manufacturer)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.ModelNumber)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.ModelNumber)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Building)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Building)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Floor)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Floor)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Corridor)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Corridor)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.RoomNo)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.RoomNo)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.MERNo)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.MERNo)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.EquipSystem)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.EquipSystem)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Comments)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Comments)
                </dd>

                <dt>
                    @Html.DisplayNameFor(model => model.Issued)
                </dt>

                <dd>
                    @Html.DisplayFor(model => model.Issued)
                </dd>

            </dl>

            @using (Ajax.BeginForm("Delete", "Asset", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "DeleteAssetSuccess" }, new { @class = "form-horizontal", role = "form" }))
            {

                <div class="form-actions no-color">
                    @Html.HiddenFor(x => x.AssetID)
                    <input type="submit" value="Delete" class="btn btn-default" /> |
                    @Html.ActionLink("Back to List", "Index",null,new { data_dismiss = "modal" })
                </div>
            }
        </div>
    </div>
</div>

现在,我们需要为 delete 弹出窗口再次添加一个容器 div,该 div 将保存来自局部视图 _DeletePartial 的响应 HTML,就像我们为其他三个操作所做的那样。因此,在 Asset Index.cshtml 视图中添加以下 HTML:

<div class="modal fade" id="deleteAssetModal" tabindex="-1" role="dialog" aria-labelledby="DeleteAssetModal" aria-hidden="true" data-backdrop="static">
    <div id="deleteAssetContainer">
    </div>
</div>

使用 JQuery 处理 Delete 链接事件

我们还需要实现 delete 按钮的单击事件,该事件将负责异步调用 action 方法并将响应 HTML 添加到弹出窗口容器中,然后将该弹出窗口容器显示给用户。代码如下:

$('#assets-data-table').on("click", ".deleteAsset", function (event) {

                event.preventDefault();

                var url = $(this).attr("href");

                $.get(url, function (data) {
                    $('#deleteAssetContainer').html(data);

                    $('#deleteAssetModal').modal('show');
                });

            });

处理 DELETE Ajax POST 成功回调

如果您注意到这里,我们仍然使用 Ajax.BeginForm 辅助方法来发布需要删除的 Asset 行的 **GUID**。我们已指定了一个 JavaScript 成功回调,但我们尚未在 **Index** 视图中定义该函数。所以,让我们也这样做。这是函数定义:

function DeleteAssetSuccess(data) {

                if (data != "success") {
                    $('#deleteAssetContainer').html(data);
                    return;
                }
                $('#deleteAssetModal').modal('hide');
                $('#deleteAssetContainer').html("");
                assetListVM.refresh();

            }

这也与我们为其他操作所做的非常相似。我们正在确保,无论删除是否成功,我们都会相应地更新 UI。这就是上面的代码所做的。它关闭弹出窗口,清除容器 div 的 HTML,并刷新 datatable ViewModel 以反映网格中的最新更改。

实现 Delete POST 操作

最后,我们需要定义 delete 的 POST 操作,该操作将负责从数据库表中删除行,并返回操作的状态给视图(无论成功还是失败)。让我们这样做。这是 Delete post 操作的代码:

        [HttpPost, ActionName("Delete")]
        public async Task<ActionResult> DeleteAsset(Guid AssetID)
        {
            var asset = new Asset { AssetID = AssetID };
            DbContext.Assets.Attach(asset);
            DbContext.Assets.Remove(asset);

            var task = DbContext.SaveChangesAsync();
            await task;

            if (task.Exception != null)
            {
                ModelState.AddModelError("", "Unable to Delete the Asset");
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                AssetViewModel assetVM = MapToViewModel(asset);
                return View(Request.IsAjaxRequest() ? "_DeletePartial" : "Delete", assetVM);
            }

            if (Request.IsAjaxRequest())
            {
                return Content("success");
            }

            return RedirectToAction("Index");

        }

现在运行该应用程序,您应该能够通过 Ajax 添加、更新和删除行,而无需在页面之间导航。

© . All rights reserved.