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

使用 ASP.NET MVC、$http & $window 服务、EF 和 CRUD 实现的第一个 AngularJs 应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (15投票s)

2015年5月5日

CPOL

10分钟阅读

viewsIcon

62330

downloadIcon

2002

在本文中,我们将使用流行的 AngularJs 库、ASP.NET MVC、$http & $window 服务和 Entity Framework 以及 Linq 来实现 CRUD 操作。

引言

在本文中,我们将使用最受欢迎的客户端库之一“AngularJs”来实现 CRUD 操作,并使用 Entity Framework & DB first 方法的 ASP.NET MVC 应用业务逻辑。

进度

我们将从创建一个全新的 ASP.NET MVC 项目开始,然后按以下步骤进行:

  1. 将 AngularJs 库添加到我们的项目,进行打包并启用优化
  2. 将 Bundle 引用添加到布局页面,并检查 Angular 是否正常工作
  3. 添加联系人列表客户端功能
  4. 使用数据库优先方法添加 EF (edmx) 并生成 POCO 类
  5. 创建带有 Linq 语句的 Repository 类以执行所有 CRUD 操作
  6. 创建一个自定义 Angular Service “Repo”来访问服务器端控制器,并
  7. 最后,创建我们的自定义 Angular Directive 并附带模板

创建全新的 ASP.NET MVC 项目

首先创建一个新的 ASP.NET MVC 项目。在此演示中,我使用了 VS 2013,包含了 MVC 核心,并且不包含 Web API 和 Web Forms。

由于本文的重点是 AngularJs,并且为了消除不必要的代码,请单击“更改身份验证”按钮,将身份验证设置为“无身份验证”。这将删除所有与身份验证相关的代码,无论是使用 Windows/Forms 还是 OWIN。

我们的项目最初看起来像这样,在“Views”文件夹中包含“Home”控制器及其相关视图。

现在,我们将向 Controllers 文件夹添加一个新的 MVC 5 空控制器“Ng”。
注意:创建控制器将自动在“Views”文件夹中添加新文件夹,用于存放其所有对应的视图。如果未添加,请在“Views”文件夹中创建一个与控制器同名的文件夹。

现在,我们将向新控制器添加第一个操作方法“NgFirst”。

[HttpGet]
public ActionResult NgFirst()
{
    return View();
}

转到并创建我们的“NgFirst”视图,右键单击 View();然后选择“添加视图…”。使用我们现有的布局页面作为其主布局。

添加控制器“Ng”和视图“NgFirst”后,我们的解决方案看起来是这样的。

将 Angularjs 库添加到我们的项目,进行打包并启用优化

现在,是时候使用“NuGet 包管理器”将 AngularJS 库添加到我们的项目了。右键单击项目引用,然后单击“管理 NuGet 程序包…”

搜索“AngularJs”,NuGet 将列出所有与 AngularJs 相关的项。在此演示中,我们只需要名为 AngularJS Core 的“核心”功能。

安装 AngularJs Core 后,将把以下 JavaScript 文件添加到Scripts文件夹。

打开位于“App_Start”文件夹中的“BundleConfig.cs”文件,创建一个指向所有 Angular js 文件的虚拟路径“ng”。

bundles.Add(new ScriptBundle("~/bundles/ng")
    .Include(
        "~/Scripts/angular.js",
        "~/Scripts/angular-mocks.js"));

BundleTable.EnableOptimizations = false;

将 Bundle 引用添加到布局页面,并检查 AngularJs 是否正常工作

打开“_Layout.cshtml”文件,添加新创建的 bundle 虚拟路径名“ng”。

注意:在 @RenderSection 标签之前,在 bootstrap 之后。

@Scripts.Render("~/bundles/ng")

另外,在布局页面的顶部导航菜单栏上添加一个新的 Action 链接“{{ng-First}}”。

<li>@Html.ActionLink("{{NgFirst}}", "NgFirst", "Ng")</li>

检查与 AngularJs 和 bundle 相关的所有内容是否设置正确,将以下标记添加到我们的“NgFirst”视图。生成并运行项目。

<div ng-app>
    <p>{{ "Hello" + " World" }}</p>
    <p>{{ 2 + 4 }}</p>
</div>

生成并运行应用程序以查看我们的“NgFirst”视图。使用 Firebug 进行检查时,应如下所示:

这意味着我们的 AngularJs 库已成功加载并成功评估了语句。

注意:如果 AngularJs 未正确加载,我们的视图将如下所示:

添加“联系人列表”客户端功能

在我们的第一个应用程序中,我们将创建一个联系人列表表单,从中获取用户输入的三个字段(名字、姓氏和电子邮件),并使用 Angular 控制器将其保存到列表中。

注意:此时我们不使用任何服务器端 MVC 或 API 控制器。我们所做的只是将数据持久化到客户端的数组对象中。

将以下 HTML 标记添加到页面

<div ng-app="ContactList" ng-controller="ContactCtrl">
    <h2>Contact Details</h2>
    <form>
        <div class="col-sm-12">
            <div><input type="hidden" ng-model="c.Id" /></div>
            <div class="col-sm-3"><input type="text" 
            placeholder="First Name" class="form-control" 
		ng-model="c.FirstName" id="firstName" /></div>
            <div class="col-sm-3"><input type="text" 
            placeholder="Last Name" class="form-control" 
		ng-model="c.LastName" /></div>
            <div class="col-sm-3"><input type="email" 
            placeholder="email@somedomain.com" 
		class="form-control" ng-model="c.Email" /></div>
            <div class="col-sm-3">
                <input type="submit" value="Save" 
                class="btn btn-primary" ng-click="addContact(c);" 
			ng-hide="IsInEditMode" />
                <input type="submit" value="Edit" 
                class="btn btn-primary" ng-click="editContact(c);" 
			ng-show="IsInEditMode" /><input type="button" value="Cancel" 
			class="btn btn-default" ng-click="clearFields();" />
            </div>
        </div>
    </form><br />
    <div ng-show="haveContacts();">
        <h2>Contact List</h2>
        <hr />
        <table class="table table-striped">
            <thead>
                <tr>
                    <td>Id</td>
                    <td>Name</td>
                    <td>Email</td>
                    <td></td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="contact in contacts">
                    <td>{{contact.Id}}</td>
                    <td>{{contact.FirstName +  " " + contact.LastName}}</td>
                    <td><span ng-bind="contact.Email"></span></td>
                    <td>
                        <button type="button" class="btn btn-primary btn-xs" 
				ng-click="doEdit(contact);">
                            <span class="glyphicon glyphicon-edit" 
                            aria-hidden="true"></span> Edit
                        </button>
                        <button type="button" class="btn btn-danger btn-xs" 
				ng-click="deleteContact(contact.Id);">
                            <span class="glyphicon glyphicon-remove" 
                            aria-hidden="true">
				</span> Delete
                        </button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

还将以下脚本添加到视图的底部

在向视图添加 JavaScript 之前,让我们先在布局页面上的 bundle 脚本语句之后添加一个scripts 部分。这允许我们将位于子/容器视图的脚本部分中的所有 JavaScript 渲染到布局脚本之后。

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/bundles/ng")

@RenderSection("scripts", required: false)

required: false”表示视图中的 JavaScript 部分不是必需的。否则,它将引发错误。

警告:视图中使用的所有脚本都必须放在script 部分内。否则,您的脚本可能无法按预期工作。

@section scripts{
<script>
var myContact = angular.module("ContactList", []);
myContact.controller("ContactCtrl", 
["$scope", "$window", function ($scope, $window) {
    $scope.contacts = [{ Id: 1, FirstName: "Sree", 
    LastName: "M", Email: "abc@bbc.com" }];
    $scope.c = { Id: 1, FirstName: "Sree", 
    LastName: "M", Email: "abc@bbc.com" };
    // Flag variable to check if the form is in edit mode - initially set to false
    $scope.IsInEditMode = false;

    clearFields = function () {
        $scope.c.Id = "";
        $scope.c.FirstName = "";
        $scope.c.LastName = "";
        $scope.c.Email = "";
        $scope.IsInEditMode = false;
    };
    $scope.clearFields = clearFields;

    addContact = function (contact) {
        if ((contact.FirstName === "") || 
        (contact.LastName === "") || (contact.Email === "")) {
            $window.alert("Input fields cannot be empty!");
            $("#firstName").focus();
        }
        else {
            var localContact = angular.copy(contact);
            if ($scope.contacts.length === 0)
                localContact.Id = 1;
            else
                localContact.Id = $scope.contacts[$scope.contacts.length - 1].Id + 1;
            $scope.contacts.push(localContact);
            clearFields();
        }
    };
    $scope.addContact = addContact;

    doEdit = function (contact) {
        var localCopy = angular.copy(contact);
        $scope.c.Id = localCopy.Id;
        $scope.c.FirstName = localCopy.FirstName;
        $scope.c.LastName = localCopy.LastName;
        $scope.c.Email = localCopy.Email;
        $scope.IsInEditMode = true;
    }
    $scope.doEdit = doEdit;

    editContact = function (xContact) {
        var localCopy = angular.copy(xContact);
        for (var i = 0; i < $scope.contacts.length; i++) {
            if (xContact.Id === $scope.contacts[i].Id) {
                $scope.contacts[i].Id = localCopy.Id;
                $scope.contacts[i].FirstName = localCopy.FirstName;
                $scope.contacts[i].LastName = localCopy.LastName;
                $scope.contacts[i].Email = localCopy.Email;
                clearFields();
                return;
            }
        }
        $scope.contacts.push(localCopy);
        clearFields();
    }
    $scope.editContact = editContact;
   
    deleteContact = function (Id) {
        if ($window.confirm("Are you sure you want to delete the contact?")) {
            for (var i = 0; i < $scope.contacts.length; i++) {
                if (Id === $scope.contacts[i].Id) {
                    $scope.contacts.splice(i, 1);
                    break;
                }
            }
        }
    }
    $scope.deleteContact = deleteContact;

    haveContacts = function () {
        return $scope.contacts.length > 0 ? true : false;
    }
    $scope.haveContacts = haveContacts;
    //clearFields();
}]);
</script>
}

以下是我们视图中使用的 Ng 指令:

  • ng-app:这表示我们在页面上声明了一个 Angular 容器,并且 ng-app 装饰元素内的所有内容都已准备好在运行时由浏览器解析 Angular 指令和求值 {{ }} 语法。
  • ng-controller:唯一负责控制 UI 的控制器。它应该只包含单个视图所需的业务逻辑。
  • ng-modelng-model 指令将输入、选择、文本区域(或自定义表单控件)绑定到作用域上的属性。它充当双向绑定指令。ng-model 将尝试通过在当前作用域上求值表达式来绑定到指定的属性。如果当前作用域上尚不存在该属性,它将被隐式创建并添加到作用域。
  • ng-click:此指令允许我们将作用域级别的对象/函数分配给元素的客户端点击事件。
  • ng-hide/ng-showng-hide/ng-show 指令根据提供给 ng-hide/ng-show 属性的表达式来显示或隐藏给定的 HTML 元素。
  • ng-repeat:允许我们循环遍历项目集合并为每个项目应用模板。
  • ng-bind:该属性指示 Angular 用给定表达式或作用域级别变量的值替换元素的内容,并在表达式发生更改时更新内容。

以下是我们视图中使用的 Ng 服务:

  • $scope:此服务通过一种机制来监视模型变化,从而实现模型和视图之间的分离。它们还提供事件发射/广播和订阅功能。
  • $window:指向浏览器窗口。此服务类似于 JavaScript 中的 window 对象。

以下是我们视图中使用的 Ng 方法:

  • Angular.copy:创建源的深层副本,源应为对象或数组。这使我们不必将对象及其 Angular 双向绑定一起复制。
  • 代码说明:在此示例中,我们创建了一个 $scope 级别的对象“c”,它将保存 Id、名字、姓氏和电子邮件的当前值。一个数组对象“contacts”用于保存添加的联系人列表,以及一个标志变量“IsInEditMode”用于保存表单的可编辑模式。我们还创建了容器方法来在客户端执行添加、编辑和删除操作。


JavaScript 代码本身解释了很多。它在客户端执行基本的 CRUD 操作。

使用数据库优先方法添加 EF (edmx) 并生成 POCO 类

现在,我们将使用 ASP.NET MVC 添加服务器端行为(CRUD)。我们将使用现有的“NgController”来处理所有 CRUD 操作,同时创建一个新的实体模型(.edmx),该模型将指向 SQL Server 数据库。

首先,让我们创建一个新数据库“FirstAngularJs”。使用以下脚本创建表“[User]”。

USE [FirstAngularJs]
GO

/****** Object:  Table [dbo].[User]    Script Date: 05/04/2015 4:06:26 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[User](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [nvarchar](50) NOT NULL,
    [LastName] [nvarchar](50) NOT NULL,
    [Email] [nvarchar](100) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,

ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

现在,我们将向Model文件夹添加一个名为“Model.edmx”的“ADO.NET 实体数据模型”。从向导中选择“从数据库生成的 EF 设计器”。

单击“下一步”,并为本次演示选择 Entity Framework 6.x 版本。
注意:在此应用程序中,我使用了 EF 版本 6。但是,我们也可以选择其他版本。

连接到您的数据库,选择“User”表。同时指定web.config文件中出现的连接字符串名称。
注意:此处给出的连接字符串名称将与我们的实体模型上下文相同。

再次单击“下一步”,并选择我们之前在 SQL Server Management Studio 中创建的表。取消选中“复数化/…”并为我们的模型设置命名空间。单击“完成”以生成 POCO(纯旧 CLR 对象)类。

注意:代码生成工具 T4(文本模板转换工具包)在实际创建我们的 POCO 类之前会产生一些警告消息。单击“确定”继续。

一切完成后,我们的实体模型看起来将是这样的:

创建带有 Linq 语句的 Repository 类以执行所有 CRUD 操作

接下来,我们将向项目根目录添加“Repository”文件夹,该文件夹通常包含与数据库交互的类。我们将添加一个名为“UserRepository.cs”的类,并使用 Linq 实现 CRUD 操作。

    public class UserRepository
    {
        private ngFirstEntitiesConStr _context;

        public UserRepository()
        {
            _context = new ngFirstEntitiesConStr();
        }

        public bool CreateUser(User model)
        {
            _context.User.Add(model);
            return (_context.SaveChanges() > 0);
        }

        public List<User> GetAllUsers()
        {
            return _context.User.ToList();
        }

        public User GetUserById(int Id)
        {
            return _context.User.Where(u => u.Id == Id).SingleOrDefault();
        }

        public bool UpdateUser(User usr)
        {
            User userToUpdate = _context.User.Where(u => u.Id == usr.Id).SingleOrDefault();
            userToUpdate.FirstName = usr.FirstName;
            userToUpdate.LastName = usr.LastName;
            userToUpdate.Email = usr.Email;
            _context.Entry(userToUpdate).State = System.Data.Entity.EntityState.Modified;
            return (_context.SaveChanges() > 0);
        }

        public bool DeleteUser(int Id)
        {
            try
            {
                User ItemToDelete = _context.User.Where(u => u.Id == Id).SingleOrDefault();
                _context.Entry(ItemToDelete).State = System.Data.Entity.EntityState.Deleted;
                return (_context.SaveChanges() > 0);
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

现在,使用新的操作方法更新我们的“NgController”,以便从存储库创建、更新、删除和获取用户联系人,如下所示:

        UserRepository repo = new UserRepository();

        [HttpPost]
        public JsonResult CreateUser(User user)
        {
            return Json(repo.CreateUser(user));
        }

        [HttpGet]
        public JsonResult GetUsers()
        {
            return Json(repo.GetAllUsers(), JsonRequestBehavior.AllowGet);
        }

        [HttpGet]
        public JsonResult GetUser(int id)
        {
            return Json(repo.GetUserById(id), JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public JsonResult UpdateUser(User user)
        {
            return Json(repo.UpdateUser(user));
        }

        [HttpPost]
        public JsonResult DeleteUser(int Id)
        {
            return Json(repo.DeleteUser(Id), JsonRequestBehavior.AllowGet);
        }

与传统地使用 jQuery Ajax 调用访问我们的控制器操作方法不同,现在我们依赖 Angular 服务($http)。这一点至关重要,因为我们将创建带有 $http 依赖项的自定义 Angular 服务。

注意:我们需要让 Angular 控制器独立于访问远程服务器方法相关的逻辑,我们必须使用自定义 Angular 服务来处理繁重的工作。

$http:此服务是核心 Angular 服务,它通过浏览器的 XMLHttpRequest 对象或 JSONP 促进与远程 HTTP 服务器的通信。

在创建 Angular 模块后立即将自定义 Angular 服务添加到我们的脚本中

// Angular service to handle all remote server interactions
myApp.service("Repo", ["$http", function ($http) {
            // Add new Contact
            this.addUser = function (usr) {
                var userObj = { "Id": usr.Id, "FirstName": 
                usr.FirstName, "LastName": usr.LastName, "Email": usr.Email }
                var config = { method: "POST", 
                url: "@Url.Action("CreateUser", "Ng")", data: userObj };
                return $http(config);
            };

            // Get All Contacts
            this.GetUsers = function () {
                return $http.get("@Url.Action("GetUsers", "Ng")");
            };

            // Get Single Contact
            this.GetUser = function (id) {
                var config = { method: "GET", 
                url: "@Url.Action("GetUser", "Ng")", data: Id };
                $http(config)
                    .success(function (data, status, header, config) {
                        alert(data);
                    }).error(function (data, status, header, config) {
                        alert("Error: Something went wrong");
                    });
            };

            // Edit Contact
            this.editUser = function (usr) {
                var userObj = { "Id": usr.Id, "FirstName": 
                usr.FirstName, "LastName": usr.LastName, "Email": usr.Email };
                var config = { method: "POST", 
                url: "@Url.Action("UpdateUser", "Ng")", data: userObj };
                return $http(config);
            };

            // Delete Contact
            this.deleteUser = function (id) {
                var userObj = { "Id": id };
                var config = { method: "POST", 
                url: "@Url.Action("DeleteUser", "Ng")", data: userObj };
                return $http(config);
            };
        }]);

如果我们查看我们的“Repo”服务,我们将 $http 服务注入到我们的处理程序中。此外,我们有几个方法可以与服务器端操作方法进行交互。我们所做的只是配置请求方法并调用 $http 服务。

基本上,配置 $http 服务需要设置操作URL方法类型(GET/POST)以及可选的要发布到服务器的数据。这是一个以 POST 方法类型将联系人详细信息作为“userObj”调用“Ng”控制器中的“CreateUser”操作方法的示例。

var userObj = { "Id": usr.Id, "FirstName": 
usr.FirstName, "LastName": usr.LastName, "Email": usr.Email }
var config = { method: "POST", 
url: "@Url.Action("CreateUser", "Ng")", data: userObj };
return $http(config);

注意$http(config) 将返回一个 Promise。使用 Promise,我们可以访问成功和/或错误回调方法。

现在,我们需要更新我们的“ContactCtrl”控制器,使其能够使用我们自定义的 Angular 服务“Repo”。我们通过将我们的自定义服务“Repo”注入到我们的控制器对象中来做到这一点。

// Controller is update with the custom Repo and window service dependancy

            myContact.controller("ContactCtrl", 
            ["$scope", "$window", function ($scope, $window) {
            $scope.contacts = [];
            $scope.c = { Id:"" , 
            FirstName: "", LastName: "", Email: "" };
            // Flag variable to check if the form is in edit mode - initially set to false
            $scope.IsInEditMode = false;

            clearFields = function () {
                $scope.c.Id = "";
                $scope.c.FirstName = "";
                $scope.c.LastName = "";
                $scope.c.Email = "";
                $scope.IsInEditMode = false;
            };
            $scope.clearFields = clearFields;

            addContact = function (contact) {
                Repo.addUser(usr)
                    .success(function (data, status, header, config) {
                        getUsers();
                        clearFields();
                        $scope.isEditMode = false;
                        $("#firstName").focus();
                    })
                    .error(function (data, status, header, config) {
                        alert("Error: Something went wrong");
                    });

                //if ((contact.FirstName === "") || 
                (contact.LastName === "") || (contact.Email === "")) {
                //    $window.alert("Input fields cannot be empty!");
                //    $("#firstName").focus();
                //}
                //else {
                //    var localContact = angular.copy(contact);

                //    if ($scope.contacts.length === 0)
                //        localContact.Id = 1;
                //    else
                //        localContact.Id = $scope.contacts[$scope.contacts.length - 1].Id + 1;

                //    $scope.contacts.push(localContact);
                //    clearFields();
                //}
            };
            $scope.addContact = addContact;

            doEdit = function (contact) {
                var localCopy = angular.copy(contact);
                $scope.c.Id = localCopy.Id;
                $scope.c.FirstName = localCopy.FirstName;
                $scope.c.LastName = localCopy.LastName;
                $scope.c.Email = localCopy.Email;
                $scope.IsInEditMode = true;
            }
            $scope.doEdit = doEdit;

            getUsers = function () {
                Repo.GetUsers()
                    .success(function (data, status, header, config) {
                        $scope.users = data;
                    })
                    .error(function (data, status, header, config) {
                        alert("Error: Something went wrong");
                    })
            };

            editContact = function (xContact) {
                Repo.editUser(usr).success(function (data, status, header, config) {
                    getUsers();
                    clearFields();
                    $scope.isEditMode = false;
                })
                .error(function (data, status, header, config) {
                    alert("Error: Something went wrong");
                });

                //var localCopy = angular.copy(xContact);
                //for (var i = 0; i < $scope.contacts.length; i++) {
                //    if (xContact.Id === $scope.contacts[i].Id) {
                //        $scope.contacts[i].Id = localCopy.Id;
                //        $scope.contacts[i].FirstName = localCopy.FirstName;
                //        $scope.contacts[i].LastName = localCopy.LastName;
                //        $scope.contacts[i].Email = localCopy.Email;
                //        clearFields();
                //        return;
                //    }
                //}
                //$scope.contacts.push(localCopy);
                //clearFields();
            }
            $scope.editContact = editContact;

            deleteContact = function (Id) {
                if ($window.confirm("Are you sure you want to delete the user 
                '" + usr.FirstName + " " + usr.LastName + "'?")) {
                    Repo.deleteUser(usr.Id).success(function (data, status, header, config) {
                        getUsers();
                        clearFields();
                        $scope.isEditMode = false;
                    }).error(function (data, status, header, config) {
                        alert("Error: Something went wrong");
                    });
                }

                //if ($window.confirm("Are you sure you want to delete the contact?")) {
                //    for (var i = 0; i < $scope.contacts.length; i++) {
                //        if (Id === $scope.contacts[i].Id) {
                //            $scope.contacts.splice(i, 1);
                //            break;
                //        }
                //    }
                //}
            }
            $scope.deleteContact = deleteContact;

            haveContacts = function () {
                return $scope.contacts.length > 0 ? true : false;
            }
            $scope.haveContacts = haveContacts;

            clearFields();
            getUsers();
        }]);

生成并运行应用程序以查看更改。执行一些创建、读取、更新和删除操作,并检查您的后端数据库。

创建我们的自定义 Angular 指令并附带模板

第一步是在脚本部分的底部创建我们的自定义 Angular Directive“contactdir”;就在我们的控制器结束的地方。

myContact.directive("contactdir", function () {
    return {
        restrict: 'EA',
        replace: true,
        templateUrl: "@Url.Content("/templates/contactrow.html")"
    };
});

指令构造函数将返回一个具有以下属性的对象:

  • restrict:这允许我们将自定义指令限制为用作元素或属性。虽然,我们可以将指令用作 CSS 类名或注释;在我们的例子中,我们将其限制为元素和属性。
  • replace:将此值设置为“true”将替换内联元素或属性;“false”值将把模板内容附加到下面的属性或元素。
  • template:内联 string,带有用作指令模板的作用域变量。
  • templateUrl:指向包含模板内容的外部文件的路径。我们的“templateUrl”指向位于“Templates”文件夹内的外部 HTML 文件。

转到并在项目根目录创建一个新文件夹“Templates”。将 tbody 元素内的表格模板行提取到一个新的 HTML 文件(ContactRow.html)中。

注意:确保从 tr 标签中删除 ng-Repeat。让其他一切保持原样。

<tr>
    <td>{{contact.Id}}</td>
    <td>{{contact.FirstName +  " " + contact.LastName}}</td>
    <td><span ng-bind="contact.Email"></span></td>
    <td>
        <button type="button" class="btn btn-primary btn-xs" ng-click="doEdit(contact);">
            <span class="glyphicon glyphicon-edit" aria-hidden="true"></span> Edit
        </button>
        <button type="button" class="btn btn-danger btn-xs" ng-click="deleteContact (contact);">
            <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Delete
        </button>
    </td>
</tr>

更新“NgFirst.cshtml”中的 tbody 元素,使其使用我们的指令,如下所示:

<tr ng-repeat="contact in contacts" contactdir></tr>

注意:我们正在通过 ng-repeat 指令将 Angular 作用域变量“contact”传递给我们的自定义“contactdir”指令。

运行应用程序,您会发现 UI 没有变化,而是通过指令对底层联系人列表进行了更改。

存储在我们 MS SQL Server 数据库中的记录。

最后,我们使用 ASP.NET MVC 和 Entity Framework 的第一个 Angular js 应用程序项目,包含 Controller(NgController)、Model(Model.edmx)、Repository(UserReposiroty.cs)和 View(NgFirst.cshtml),看起来如下:

关注点

作为我们第一个 Angular js 应用程序与 ASP.NET MVC 和 Entity Framework 的一部分,我们使用了以下 Angular 特定的指令、服务或方法:

  1. ng-app
  2. ng-controller
  3. ng-directive
  4. ng-model
  5. ng-bind 或 {{ expression }}
  6. ng-click
  7. ng-hide
  8. ng-show
  9. ng-repeat
  10. $scope
  11. $http
  12. $window
  13. angular.module
  14. angular.copy

希望通过本文您学到了一些新东西,并能够使用 AngularJs 执行一些基本操作。欢迎评分、评论和提出建议。

© . All rights reserved.