SharePoint 2013 和 Angularjs






4.60/5 (20投票s)
充分利用 AngularJS 在 SharePoint 2013 中的双向数据绑定优势。AngularJS 可用于内容编辑器 Web 部件或 SharePoint 应用。
引言
我们都知道 AngularJS 目前是最著名的双向数据绑定框架。本文旨在展示如何在 SharePoint 2013 中利用这一优势(双向数据绑定)。在阅读本文之前,您必须具备 AngularJS 和 SharePoint 2013 REST API 的知识。
AngularJS 可以帮助我们开发内容编辑器 Web 部件和应用。在大多数情况下,我发现人们会选择沙盒解决方案,但 SharePoint 2013 的 REST API 非常强大,可以轻松地用内容编辑器 Web 部件或应用取代沙盒解决方案。在本文中,我们将看到如何在内容编辑器 Web 部件和 SharePoint 托管应用中使用 AngularJS。
初始设置
为了保持一切简单,我将演示一个对列表的 CRUD 操作,因为我们知道 CRUD 是任何业务需求中非常常见的组成部分。我将列表命名为 People
。除此之外,您还需要 SharePoint Designer 2013 和 Visual Studio 2013 或 2012。最后,请确保您的服务器已准备好开发 SharePoint 托管应用。
以下功能将实现,例如查看所有项目和删除项目。
添加新项目
编辑项目
内容编辑器 Web 部件中的 AngularJs
如果您不熟悉内容编辑器 Web 部件,请在此处查看了解详情。现在,从 Designer,在任何资产库中创建一个文件夹,然后创建一个文本文件。在我的例子中,我创建了一个名为 People 的文件夹,并在 Site Assets 库中创建了一个名为 people-main.txt的文本文件。最后,将此文件的 URL 添加到 Content Link。我的 URL 变为 /SiteAssets/People/people-main.txt ,因为我使用的是我的根网站集。如果您更喜欢在任何子网站工作,请正确添加其路径到 URL。
现在文本文件已准备好添加 HTML 代码。
<link href="/SiteAssets/People/css/style.css" rel="stylesheet" type="text/css">
<script src="/SiteAssets/People/lib/angular.min.js" type="text/javascript"></script>
<script src="/SiteAssets/People/lib/angular-route.min.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/app.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/services/baseSvc.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/services/people/people.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/controllers/people/all.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/controllers/people/add.js" type="text/javascript"></script>
<script src="/SiteAssets/People/js/controllers/people/edit.js" type="text/javascript"></script>
<div data-ng-app="peopleApp">
<div data-ng-view class="people-app"></div>
</div>
实际上,在这个文件中,我添加了必要的脚本源并初始化了 ng-app
和 ng-view
。除此之外,我还在这里链接了 css
文件。
现在让我们看看脚本文件。一切都与典型的 AngularJS 应用非常相似。现在让我解释一下有什么不同。
app.js
"use strict";
(function() {
angular.module("peopleApp", ["ngRoute"])
.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/", {
templateUrl: "/SiteAssets/People/templates/people/all.html",
controller: "allPeopleCtrl"
}).when("/addPerson", {
templateUrl: "/SiteAssets/People/templates/people/add.html",
controller: "addPersonCtrl"
}).when("/editPerson/:personId", {
templateUrl: "/SiteAssets/People/templates/people/edit.html",
controller: "editPersonCtrl"
});
}]);
})();
这里创建了 peopleApp
并定义了必要的路由。
baseSvc.js
"use strict";
(function() {
angular.module("peopleApp")
.factory("baseSvc", ["$http", "$q", function($http, $q) {
var baseUrl = _spPageContextInfo.webAbsoluteUrl;
var getRequest = function(query) {
var deferred = $q.defer();
$http({
url: baseUrl + query,
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
"content-Type": "application/json;odata=verbose"
}
})
.success(function(result) {
deferred.resolve(result);
})
.error(function(result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var postRequest = function(data, url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "POST",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"content-Type": "application/json;odata=verbose"
},
data: JSON.stringify(data)
})
.success(function(result) {
deferred.resolve(result);
})
.error(function(result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var updateRequest = function(data, url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "PATCH",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"content-Type": "application/json;odata=verbose",
"X-Http-Method": "PATCH",
"If-Match": "*"
},
data: JSON.stringify(data)
})
.success(function(result) {
deferred.resolve(result);
})
.error(function(result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var deleteRequest = function(url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "DELETE",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"IF-MATCH": "*"
}
})
.success(function(result) {
deferred.resolve(result);
})
.error(function(result, status) {
deferred.reject(status);
});
return deferred.promise;
};
return {
getRequest: getRequest,
postRequest: postRequest,
updateRequest: updateRequest,
deleteRequest: deleteRequest
};
}]);
})();
我创建了一个通用的服务,用于所有类型的请求,如 GET
、POST
、UPDATE
和 DELETE
,以便我们可以从任何地方注入它。我在这里不描述这些方法是如何工作的,因为我有一个关于它的另一个文章。在那篇文章中,我使用 jQuery 进行了演示,在这篇文章中我将其转换为 AngularJS。这个 baseSvc
被注入到 peopleService
中,使我们在获取、添加、更新和删除项目时避免了重复代码。在发送任何请求之前,您必须将所需的 URL 和参数传递给 baseSvc
方法。
"use strict";
(function() {
angular.module("peopleApp")
.factory("peopleService", ["baseSvc", function(baseService) {
var listEndPoint = '/_api/web/lists';
var getAll = function() {
var query = listEndPoint + "/GetByTitle('People')/Items?$select=ID,
FirstName,LastName,Address";
return baseService.getRequest(query);
};
var addNew = function(person) {
var data = {
__metadata: {
'type': 'SP.Data.PeopleListItem'
},
FirstName: person.firstName,
LastName: person.lastName,
Address: person.address
};
var url = listEndPoint + "/GetByTitle('People')/Items";
return baseService.postRequest(data, url);
};
var getById = function(personId) {
var query = listEndPoint + "/GetByTitle('People')/GetItemById
(" + personId + ")?$select=ID,FirstName,LastName,Address";
return baseService.getRequest(query);
};
var update = function(person) {
var data = {
__metadata: {
'type': 'SP.Data.PeopleListItem'
},
FirstName: person.firstName,
LastName: person.lastName,
Address: person.address
};
var url = listEndPoint + "/GetByTitle('People')/
GetItemById(" + person.personId + ")";
return baseService.updateRequest(data, url);
};
var remove = function(personId) {
var url = listEndPoint + "/GetByTitle('People')/
GetItemById(" + personId + ")";
return baseService.deleteRequest(url);
};
return {
getAll: getAll,
addNew: addNew,
getById: getById,
update: update,
remove: remove
};
}]);
})();
您可能会问,我是如何为每个请求构建 URL 和参数的。同样,您需要查看这篇文章。
现在让我们看看模板和控制器。
所有项目
此模板用于显示项目和删除项目。
<a href="#/addPerson" class="add-new-button">Add New Person</a>
<div class="all-people">
<table>
<tbody>
<tr>
<th>Fist Name</th>
<th>Last Name</th>
<th>Address</th>
<th>Action</th>
</tr>
<tr data-ng-repeat="person in people">
<td>{{person.FirstName}}</td>
<td>{{person.LastName}}</td>
<td>{{person.Address}}</td>
<td>
<a href="#/editPerson/{{person.ID}}">
<img src="/SiteAssets/People/images/edit.png" alt=""></a>
<a href="" data-ng-click="removePerson(person)">
<img src="/SiteAssets/People/images/delete.png" alt=""></a>
</td>
</tr>
</tbody>
</table>
</div>
此视图的相应控制器如下所示:
"use strict";
(function () {
angular.module("peopleApp")
.controller("allPeopleCtrl", ["$scope", "peopleService",
function ($scope, peopleService) {
peopleService.getAll()
.then(function (response) {
$scope.people = response.d.results;
});
$scope.removePerson = function(person){
peopleService.remove(person.ID)
.then(function(response){
var personIndex = $scope.people.indexOf(person);
$scope.people.splice(personIndex,1);
});
};
}]);
})();
您必须注意到,我在 peopleService
中使用 getAll()
请求了 ID
、FirstName
、LastName
和 Address
。在此控制器中,peopleService
返回的项目使用 ng-repeat
绑定到视图。删除项目也在这里实现。我在这里不描述其他视图和控制器,因为这会不必要地冗长。希望您在下载我的源代码后会理解一切。
注意:不要在模板中使用任何 form 标签。
托管应用中的 AngularJS
在开发本地环境的托管应用之前,必须正确配置环境。在这种情况下,Office-365 要容易得多。根本不需要进行环境配置。现在,通过选择开发人员网站模板创建一个开发人员网站集。我们不能使用除开发人员网站以外的任何其他网站进行应用开发。现在,在此网站中添加相同的People列表。
在 Visual Studio 中创建一个新项目,并从 Office/SharePoint 模板中选择 App for SharePoint 2013。
点击确定,输入您想要用于调试的网站 URL,选择 SharePoint-Hosted,然后点击完成。
当我们创建一个 SharePoint 托管应用时,它会为我们的脚本和设计文件提供一个标准的文件夹结构。我们不能按照我们在内容编辑器中所做的那样做。我已将文件添加到以下结构中:
基本上,我已将所有脚本添加到 Scripts 文件夹,样式添加到 Content 文件夹,图片添加到 Images 文件夹。对于模板文件,我添加了一个名为Templates的新文件夹。现在,打开 Default.aspx 页面并按以下方式修改它:
<%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%>
<%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,
Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
MasterPageFile="~masterurl/default.master" Language="C#" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages"
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%-- The markup and script in the following Content element
will be placed in the <head> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<meta name="WebPartPageExpansion" content="full" />
<link rel="Stylesheet" type="text/css" href="../Content/style.css" />
<script src="../Scripts/angular.min.js" type="text/javascript"></script>
<script src="../Scripts/angular-route.min.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/app.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/services/baseSvc.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/services/people/people.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/controllers/people/all.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/controllers/people/add.js" type="text/javascript"></script>
<script src="../Scripts/peopleApp/controllers/people/edit.js" type="text/javascript"></script>
</asp:Content>
<asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
SharePoint 2013 Hosted App and AngularJS Demo
</asp:Content>
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
<div data-ng-app="peopleApp">
<div data-ng-view class="people-app"></div>
</div>
</asp:Content>
在此页面中,我添加了所有脚本和样式引用,并在此处初始化了 peopleApp
。现在,app.js 和 baseSvc.js 文件有一些小的改动。在 app.js 中,我们必须按以下方式更改模板 URL:
"use strict";
(function () {
angular.module("peopleApp", ["ngRoute"])
.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("/", {
templateUrl: "../Templates/people/all.html",
controller: "allPeopleCtrl"
}).when("/addPerson", {
templateUrl: "../Templates/people/add.html",
controller: "addPersonCtrl"
}).when("/editPerson/:personId", {
templateUrl: "../Templates/people/edit.html",
controller: "editPersonCtrl"
});
}]);
})();
在 baseSvc.js 文件中,我们必须使用 _spPageContextInfo.siteAbsoluteUrl
而不是 _spPageContextInfo.webAbsoluteUrl
作为 baseUrl
。
var baseUrl = _spPageContextInfo.siteAbsoluteUrl;
我们已经完成了使用 AngularJS 开发 SharePoint 托管应用的工作。另外,我必须提到,每当您将任何文件添加到项目中时,请检查相应的 Elements.xml
文件。脚本、内容和图片都有自己的 Elements.xml
文件。例如,我将模板文件添加到了 Templates 文件夹中,所以我的主 Elements.xml 文件应如下所示:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="RootModule">
<File Path="Templates\people\add.html"
Url="Templates/people/add.html" ReplaceContent="TRUE" />
<File Path="Templates\people\all.html"
Url="Templates/people/all.html" ReplaceContent="TRUE" />
<File Path="Templates\people\edit.html"
Url="Templates/people/edit.html" ReplaceContent="TRUE" />
</Module>
</Elements>
现在右键单击您的项目并点击部署。我希望您会在浏览器中看到以下视图:
结论
希望您喜欢这篇文章。现在下载我的源代码,并以您自己的方式开始深入研究。对于问题和建议,请使用评论部分。