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

MVC 与 Ajax - 初学者入门(第 3 部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (13投票s)

2014年3月31日

CPOL

10分钟阅读

viewsIcon

44704

downloadIcon

1349

这是一个关于如何在 MVC 中使用 Ajax 的快速教程,在一个页面中实现所有基本的添加、更新、编辑和删除功能。

引言

正如我所承诺的,本文是本系列第一部分和第二部分中 MVC 的进一步进展。在这里,我们将使用 Ajax/Jquery 来实现我们之前完成的相同功能。

众所周知,Web 的核心在于服务的速度,而最快的客户端服务方式无疑需要 Ajax,因为它会减少数据交换,或者我们可以说只交换必要的数据,从而避免带宽浪费并提供更好的性能。此外,它还为您的应用程序提供了一个更具交互性的界面。那么,让我们开始 MVC + Ajax 吧。

背景

我们将在项目中利用一些新术语/技术来实现 Ajax。当您通读本文时,您将获得关于这些的简要信息。因此,如果您对它们有所了解,那将是很好的。这些是“Bundling”和“PartialViews”。

捆绑和压缩:这既不是一个新概念,也不复杂。实际上,它非常简单,我将在本文后面解释。

部分视图:这些是 Razor 视图页面,但它们可以被重用。如果您想在 Web 应用程序中重用一个视图,您可以使用部分视图概念。部分视图就像一个带有文件扩展名“.cshtml”的常规视图。我们可以在需要为 MVC Web 应用程序重用页眉、页脚的情况下使用部分视图。我们可以说它类似于 ASP.NET 中的用户控件概念。

因此,有了这些非常基础的知识,您就可以继续了。此外,随着文章的进展,您将详细了解它们。

使用代码

在我们开始 MVC 与 Ajax 之前,有几个要点需要考虑。由于 Ajax 与 Jquery 库一起工作,所以必须包含 Jquery 库,并且您会在 Scripts 文件夹中找到一些附加文件(见下图),即“jquery.unobtrusive-ajax.js”及其压缩版本,它负责 MVC 中使用 Ajax 的所有 Ajax 回发。

所以如果你忘记添加这个文件,你的 Ajax 代码块将不起作用,并将执行正常的 PostBack。

将文件包含在捆绑中

包含此 JavaScript 文件有多种方法,但必须选择不影响性能的最有效方法。到目前为止,所有文件(css 或 js)都从我们的“_Layout.cshtml”页面中包含,该页面充当主题的母版页。它位于“Views/Shared”文件夹中。所以打开该页面,您会在底部看到以下几行

在这里,您可以看到我们在此命名空间下添加了文件捆绑(我们可以说这只是逻辑分离)。这里就涉及到了“捆绑和压缩”的作用。

捆绑和小型化

这是一个过程,通过它我们创建在整个应用程序中所需的文件捆绑,并在应用程序加载时注册这些文件,从而避免它们一次又一次地加载。这将避免带宽浪费,缩短加载时间,最终获得更好的性能。

要将文件添加到捆绑包中,我们必须遵循以下步骤

1. 转到应用程序根文件夹中的“App_Start”文件夹。

2. 打开名为“BundleConfig.cs”的文件。此文件包含我们创建的捆绑包的配置

3. 添加新的捆绑包或修改现有的捆绑包。现在,如果您要添加一些具有特殊情况(例如手动验证)的文件,您可以创建新的捆绑包,否则最好将文件添加到最相关的捆绑包。在我们的应用程序中,我们将把“ajax.unobtrusive.ajax.min.js”文件添加到我们现有的捆绑包中。下面是其快照。

在这里您可以看到我们没有添加完整的文件路径,而是只添加了“jquery.unobtrusive*”。此功能使应用程序能够避免命名问题,例如在我们的示例中,它将包含名称以“jquery.unobtrusive”开头的文件。

您还会注意到,“{version}”一词出现在上面捆绑块的第二行。这用于避免版本问题。如果您有同一文件的两个版本,它将自动包含更高版本的文件。

通过这种方式,我们添加了js文件或css或任何我们想要注册的文件。现在我们准备好在我们的第一个 MC 应用程序中使用 Ajax 功能。现在让我们开始在 MVC 中实现 Ajax

预期输出

通过使用 Ajax,我们将创建一个单页应用程序,用户可以在其中

  1. 添加记录。
  2. 编辑现有记录。
  3. 删除现有记录。

所以下面是本文我们将要实现内容的截图

在这里您可以看到,左侧是与系列早期部分中添加的相同的用于查看、编辑或删除已保存记录的网格,右侧是与第一部分或系列中相同的视图。

简而言之,我们将把这两个页面合并成一个,并使用 Ajax 在这些视图之间进行通信,从而在单个页面上实现相同的功能。

添加新控制器

添加一个新控制器。给它一个合适的名称。我把它命名为FirstAjaxController’,这样我们就能很容易地识别出它将在其中实现 Ajax。默认情况下,您会在此控制器中有一个 Index 方法,并在Views/FirstAjax文件夹中有一个该方法的 Index 视图。

现在,正如我上面提到的,我们将把两个页面视图合并到一个页面中,这里出现的问题是,我们针对两种情况有不同类型的视图,即在系列的第一部分中,我们将视图类型转换为“@model StartWithMVC.Models.Employee”,而在第二部分中,我们已将视图类型转换为(强类型)“@model List<StartWithMVC.Models.Employee>”。那么,我们如何在单个页面中处理这个问题呢?为此,我们有一些技术。通过使用它们,我们可以实现我们的逻辑。可以选择任何一种技术,但清晰和更好的方法总是首选。要深入了解这些,您可以学习以下文章

https://codeproject.org.cn/Articles/687061/Using-Multiple-Models-in-a-View-in-ASP-NET-MVC-M

在我们的应用程序中,为了解决这个问题,我们将使用“Tuple”技术。在此技术中,我们将创建一个新类或模型,它可以对多种数据类型进行分组。因此,

  1. 添加新的模型文件夹并给它一个合适的名称(我把它命名为“AddUpdateEmployee.cs”)
  2. 在该类/模型中写入以下代码行
public Employee EmpModel { get; set; }

public List<Employee> ListEmpModel { get; set; }

这里第一行包含 Employee Model 对象,第二行包含 List 类型 employee Model 对象。因此,如果我们将视图强类型转换为这个对象,我们就可以将两个模型继承到一个模型中。您将看到我们如何在应用程序中使用此模型。

这是如果遇到任何问题/困惑时,它将如何进行的屏幕截图。

添加/更新索引视图

现在,通过右键单击控制器(FirstAjaxController.cs)中的 Index 方法,转到“index.cshtml”。现在在该文件中编写以下代码

@model StartWithMVC.Models.AddUpdateEmployee

@{

    ViewBag.Title = "Index";

}


<h2>Employee</h2>

<div id="divListPanel" class="left_panel">

    @Html.Partial("_ViewAllRecords", Model.ListEmpModel)

</div>


<div id="divEditPanel" class="right_panel">

    @Html.Partial("_UpdateEmployee", Model.EmpModel)

</div>

现在,您可以看到我们在此视图中使用了“AddUpdateEmployee”元组,并且我们进一步使用此模型来获取所需的 Employee 和 List<Employee> 类型对象。

为什么使用局部视图?

因为 Ajax 在响应中返回完整的页面 HTML,并用整个页面 HTML 更新目标 div,从而导致页面中又打开一个页面。为了避免这种情况,我们只为我们想要在任何特定操作中更新的部分创建局部视图。

1. 局部视图 "_ViewRecord"

 @model List<StartWithMVC.Models.Employee>

<div class="table_container">

    <table>

        <thead>

            <th>HR Emp Id</th>

            <th>Last Name</th>

            <th>First Name</th>

            <th>City</th>

            <td><b>Edit</b></td>

            <td><b>Delete</b></td>

        </thead>

        <tbody>

            @foreach (var item in Model)

            {

                <tr>

                    <td>@item.HREmpId</td>

                    <td>@item.LastName</td>

                    <td>@item.FirstName</td>

                    <td>@item.City</td>

                    <td>@Ajax.ActionLink("Edit", "EditRecord", new { recordID = @item.EmpId }, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divEditPanel" })</td>

                    <td>@Ajax.ActionLink("Delete", "DeleteRecord", new { recordID = @item.EmpId }, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divListPanel" })</td>

                </tr>

            }

        </tbody>

        </table>

</div>

如您所见,这与我们在第2部分视图中使用的完全相同。我们所做的唯一更改如下

如您所见,这里我们使用了 '@Ajax.ActionLink' 而不是 '@Html.ActionLink',从而引入了 Ajax。这里我们添加了一个 AjaxOption 属性,它将设置 Ajax 调用的处理方式。在这里,我们告诉 Ajax 我们希望在此 Ajax 调用中替换 'divEditPanel' 的内容。

同样,在删除链接上,我们告诉 Ajax 我们希望更新“divListPanel”,即左侧面板的内容。

2.局部视图"_UpdateEmployee"

@model StartWithMVC.Models.Employee
@using (Ajax.BeginForm("SaveEmployee", "FirstAjax", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divListPanel", OnComplete="resetFields();" }))
{
    <fieldset>
        @Html.HiddenFor(m => m.EmpId)
    <p>
        @Html.LabelFor(m => m.HREmpId)
        @Html.TextBoxFor(m => m.HREmpId, new { maxlength = 10 })
    </p>
    <p>
        @Html.LabelFor(m => m.FirstName)
        @Html.TextBoxFor(m => m.FirstName, new { maxlength = 30 })
    </p>
    <p>
        @Html.LabelFor(m => m.LastName)
        @Html.TextBoxFor(m => m.LastName, new { maxlength = 30 })
    </p>
        <p>
        @Html.LabelFor(m => m.Address)
        @Html.TextBoxFor(m => m.Address, new { maxlength = 30 })
    </p>
    <p>
        @Html.LabelFor(m => m.City)
        @Html.TextBoxFor(m => m.City, new { maxlength = 30 })
    </p>
    </fieldset>
    
    <input type="submit" name="btnSave" value="Submit" />
}

这里我们也使用了与之前(第一部分)相似的代码,但我们所做的唯一改变是通过使其成为 Ajax 提交表单,将 Ajax 引入了表单。

因此,这将通过点击执行 Ajax 请求,并调用“resetFields()”JavaScript 函数来清除右侧区域的字段。下面是 JavaScript 函数

<script type="text/javascript">
    function resetFields() {
        $('input[type=text]').val('');
    }
</script> 

这就是所有视图方面的内容,现在我们将看看控制器中的变化。

控制器动作代码块

1. 索引动作

在控制器中的 index 方法中写入以下几行。

 StartWithMVCEntities db = new StartWithMVCEntities();
            var tempModel = new AddUpdateEmployee();
            tempModel.EmpModel = new Employee();
            tempModel.ListEmpModel = db.Employees.ToList();
            return View(tempModel); 

如您所见,我在这里使用了tempModel tuple模型,并分配了一个 Employee 模型对象和 List <Employee> 对象,然后将其传递给视图。现在检查上面 'Index.cshtml' 视图代码,我们在那里使用了它。因此,我们可以通过多个模型来服务一个视图。

2. 保存/更新员工操作

写入以下代码以保存员工。您会注意到此方法与文章系列第二部分中编写的方法有一些变化。

 public ActionResult SaveEmployee(Employee objEmployee)
        {
            StartWithMVCEntities db = new StartWithMVCEntities();
            if (objEmployee != null && objEmployee.EmpId != 0)
            {
                //TODO : your entity framework code for updateing the employee details
                //fetch object for the editted employee record
                Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == objEmployee.EmpId);
                //Assign the edited value to getch object
                objEmp.HREmpId = objEmployee.HREmpId;
                objEmp.FirstName = objEmployee.FirstName;
                objEmp.LastName = objEmployee.LastName;
                objEmp.Address = objEmployee.Address;
                objEmp.City = objEmployee.City;
                //finally save the chagne to database
                db.SaveChanges();
                //this line will reset the default model state or properties
                ModelState.Clear(); 
                List<Employee> listEmpModel = db.Employees.ToList();
                return PartialView("_ViewAllRecords", listEmpModel);
            }
            else
            {
                //TODO : your entity framework code for saving the employee details
                db.Employees.AddObject(objEmployee);
                db.SaveChanges();
                //this line will reset the default model state or properties
                ModelState.Clear();
                List<Employee> listEmpModel = db.Employees.ToList();
                return PartialView("_ViewAllRecords", listEmpModel);
            }
        } 
注意事项

现在很清楚,如果保存或更新任何员工,那么它应该在左侧的视图记录列表中显示/反映更改。因此,我们只需要更新该部分,并在完成后重置字段。为此,以下几行非常重要

ModelState.Clear();return PartialView("_ViewAllRecords", listEmpModel);

modelstate.clear():这将重置模型状态,并在保存和更新时重新初始化表单,从而使保存和更新操作保持独立。因此,在添加的情况下,我们用于保存函数比较的主键值将为零,而在更新情况下,它将为非零。

在 'return PartialView("_ViewAllRecords", listEmpModel);' 行中,我返回了由该局部视图生成的视图,同时我还传递了该局部视图所需的列表模型。

因此,我们得到了所需的输出,而无需完全加载页面,并且只更新了所需的部分/区域,从而提高了性能。

现在要重置字段,我调用了上面编写的 JavaScript 函数。这非常简单。

3. 编辑记录(使记录可编辑)

现在,当我们在视图记录网格中单击“编辑”链接时,需要将值显示在字段中,因此很明显我们需要更新右侧部分,或者我们可以说“_UpdateEmployee”视图。下面是具有类似更改的代码。

public ActionResult EditRecord(int recordID)
        {
            //TODO : your entity framework code for showing the employee details
            StartWithMVCEntities db = new StartWithMVCEntities();
            Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == recordID);
             
            return PartialView("_UpdateEmployee", objEmp);
        }  

4. 删除记录

现在,当我们从网格中删除记录时,我们只需要更新左侧部分,或者说只更新“_ViewRecords”视图,我们也将这样做。下面是相应的代码

 public ActionResult DeleteRecord(int recordID)
        {
            //TODO : your entity framework code for showing the employee details
            StartWithMVCEntities db = new StartWithMVCEntities();
            Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == recordID);
            db.Employees.DeleteObject(objEmp);
            db.SaveChanges();
            List<Employee> listEmpModel = db.Employees.ToList();
            return PartialView("_ViewAllRecords", listEmpModel);
        } 

运行项目

现在我们已经准备好运行应用程序了。您会看到与我开头提到的相似的视图。因此,我们已经实现了我们的目标。

注意:您的视图可能与我提供的图片有一些设计上的差异,这仅是由于某些 CSS“样式表”造成的。那不是我们讨论的一部分,所以我没有包含它。如果您希望拥有它,请下载上面附件中的源代码。

关注点

因此,我们刚刚看到了如何将 Ajax 与 MVC 结合使用,以在同一页面上实现所有添加、更新和删除记录,同时最大限度地减少服务器负载。现在,正如前面提到的,感兴趣的要点是

  • 部分视图
  • 捆绑和小型化
  • Ajax Js 文件
© . All rights reserved.