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

SharePoint 2013 和 Angularjs

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (20投票s)

2015年8月12日

CPOL

5分钟阅读

viewsIcon

181376

downloadIcon

3330

充分利用 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 托管应用

people-list

以下功能将实现,例如查看所有项目删除项目

all

添加新项目

add

编辑项目

edit

内容编辑器 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-appng-view。除此之外,我还在这里链接了 css 文件。

folder-structure

现在让我们看看脚本文件。一切都与典型的 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
            };
        }]);
})();

我创建了一个通用的服务,用于所有类型的请求,如 GETPOSTUPDATEDELETE,以便我们可以从任何地方注入它。我在这里不描述这些方法是如何工作的,因为我有一个关于它的另一个文章。在那篇文章中,我使用 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() 请求了 IDFirstNameLastNameAddress。在此控制器中,peopleService 返回的项目使用 ng-repeat 绑定到视图。删除项目也在这里实现。我在这里不描述其他视图和控制器,因为这会不必要地冗长。希望您在下载我的源代码后会理解一切。

注意:不要在模板中使用任何 form 标签。

托管应用中的 AngularJS

在开发本地环境的托管应用之前,必须正确配置环境。在这种情况下,Office-365 要容易得多。根本不需要进行环境配置。现在,通过选择开发人员网站模板创建一个开发人员网站集。我们不能使用除开发人员网站以外的任何其他网站进行应用开发。现在,在此网站中添加相同的People列表。

在 Visual Studio 中创建一个新项目,并从 Office/SharePoint 模板中选择 App for SharePoint 2013。

New Project

点击确定,输入您想要用于调试的网站 URL,选择 SharePoint-Hosted,然后点击完成。

Url selection

当我们创建一个 SharePoint 托管应用时,它会为我们的脚本和设计文件提供一个标准的文件夹结构。我们不能按照我们在内容编辑器中所做的那样做。我已将文件添加到以下结构中:

app-folder

基本上,我已将所有脚本添加到 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.jsbaseSvc.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>

现在右键单击您的项目并点击部署。我希望您会在浏览器中看到以下视图:

app home

结论

希望您喜欢这篇文章。现在下载我的源代码,并以您自己的方式开始深入研究。对于问题和建议,请使用评论部分。

© . All rights reserved.