SharePoint REST API 和 AngularJs (适用于 2013, 2016 和 Online)






3.86/5 (5投票s)
SharePoint 和 AngularJs 以及 HTTP 请求,例如 GET, POST, UPDATE, DELETE 和使用 AngularJS 进行文件上传
引言
此示例包含一个可重用的 angularjs 模块。该模块包含一个服务和一个指令。任何人都可以通过依赖注入使用此模块。这适用于希望利用 SharePoint 客户端开发中双向数据绑定的用户。在客户端开发中,我们基本上会向一些特定的端点发出 GET, POST, UPDATE 和 DELETE 请求。因此,此模块将为您节省编写任何 HTTP 请求的代码冗余。该模块适用于内容编辑器 Web 部件和 SharePoint 托管应用开发。
开始之前
目标用户在使用此模块之前需要具备以下知识。我将在下面提供一些相关内容的参考。
当前问题
获取所有列表的典型 GET 请求如下所示:
function getAllLists() {
    $http({
        url: "/_api/web/lists"
            method: "GET",
        headers: {
            "accept": "application/json;odata=verbose",
            "content-Type": "application/json;odata=verbose"
        }
    }).success(function(result) {
        //do something here
    }).error(function(error, status) {
        // do something here
    });
}
而获取特定列表所有项目的 GET 请求如下所示:
function getAllItems() {
    $http({
        url: "/_api/web/lists/GetByTitle('List Title')/Items"
            method: "GET",
        headers: {
            "accept": "application/json;odata=verbose",
            "content-Type": "application/json;odata=verbose"
        }
    }).success(function(result) {
        //do something here
    }).error(function(error, status) {
        // do something here
    });
}
这些函数的作用不同,但它们共享大部分代码。因此,该模块负责处理 GET, POST, UPDATE 和 DELETE 请求的所有繁琐工作。您只需传递您的 data 和 url 即可发出任何类型的请求。此模块的源代码如下所示:
(function() {
    'use strict';
    angular.module('spNgModule', []).factory
    ("spBaseService", spBaseService).directive("customFileChange", customFileChange);;
    spBaseService.$inject = ["$q", "$http", "IS_APP_WEB"];
    function spBaseService($q, $http, isAppWeb) {
        var baseUrl = isAppWeb ? _spPageContextInfo.webAbsoluteUrl : 
                                 _spPageContextInfo.siteAbsoluteUrl;
        return {
            getRequest: getRequest,
            postRequest: postRequest,
            updateRequest: updateRequest,
            deleteRequest: deleteRequest,
            fileUploadRequest: fileUploadRequest,
            baseUrl: baseUrl
        };
        function getRequest(query, endPoint) {
            var deferred = $q.defer();
            $http({
                url: endPoint || 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({
                    error: result,
                    status: status
                });
            });
            return deferred.promise;
        }
        function postRequest(data, url, endPoint) {
            var deferred = $q.defer();
            $http({
                url: endPoint || 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({
                    error: result,
                    status: status
                });
            });
            return deferred.promise;
        }
        function fileUploadRequest(data, url, endPoint) {
            var deferred = $q.defer();
            $http({
                url: endPoint || baseUrl + url,
                method: "POST",
                processData: false,
                data: data,
                transformRequest: angular.identity,
                headers: {
                    "accept": "application/json;odata=verbose",
                    "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
                    "Content-Type": undefined
                }
            }).success(function(result) {
                deferred.resolve(result);
            }).error(function(result, status) {
                deferred.reject({
                    error: result,
                    status: status
                });
            });
            return deferred.promise;
        }
        function updateRequest(data, url, endPoint) {
            var deferred = $q.defer();
            $http({
                url: endPoint || 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({
                    error: result,
                    status: status
                });
            });
            return deferred.promise;
        }
        function deleteRequest(url, endPoint) {
            var deferred = $q.defer();
            $http({
                url: endPoint || 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({
                    error: result,
                    status: status
                });
            });
            return deferred.promise;
        }
    }
    customFileChange.$inject = ["$parse"];
    function customFileChange($parse) {
        return {
            restrict: "A",
            link: function(scope, element, attrs) {
                var model = $parse(attrs.customFileChange);
                var modelSetter = model.assign;
                element.bind("change", function() {
                    scope.$apply(function() {
                        var reader = new FileReader();
                        reader.onload = function(e) {
                            var fileModel = {
                                fileName: element[0].files[0].name,
                                fileAsBuffer: e.target.result
                            };
                            modelSetter(scope, fileModel);
                        }
                        reader.onerror = function(e) {
                            alert(e.target.error);
                        }
                        reader.readAsArrayBuffer(element[0].files[0]);
                    });
                });
            }
        };
    }
})(window, document);
此模块包含的内容
- getRequest(query, endPoint)
- postRequest(data, url, endPoint)
- updateRequest(data, url, endPoint)
- deleteRequest(url, endPoint)
- fileUploadRequest(data, url, endPoint)
endPoint 在所有地方都是可选的。稍后将讨论其用法。您将能够使用支持 GET, POST, UPDATE 和 DELETE 请求的这些端点。每个方法都会返回一个 Promise,您需要在代码中对其进行处理。
如何使用
首先,从附件下载此模块。附件包含我的模块的最小化和非最小化版本。下载文件后,请在您的项目中添加引用。例如,在 SharePoint 托管应用中,应如下所示:
<script src="../Scripts/App/spNgModule.js"></script>
在内容编辑器 Web 部件中,您需要将此文件上传到某个库,然后才能使用它。
在模块中添加依赖
您可以通过以下方式将此依赖项添加到您的模块中。此模块的名称是 spNgModule。
(function () {
    angular.module("spNgModuleTest", ["spNgModule"])
    .constant("IS_APP_WEB", false);
})();
在这里,您需要指定 IS_APP_WEB 的值。这意味着将使用哪个 Web URL 来发出 GET, POST, UPDATE 和 DELETE 请求。在指定 IS_APP_WEB 的值之后,您还可以使用其他 URL 来发出任何请求。这就是为什么有一个名为 endPoint 的可选参数。
注意:如果您在请求中指定了 endPoint,那么 url 参数将是可选的。默认情况下,所有请求都将基于 IS_APP_WEB 的值发出。无论是 APP Web 还是 Host Web。
注入服务
我使用的服务名称是 spBaseService。因此,您可以按以下方式注入此服务:
angular.module("spNgModuleTest")
    .factory("spNgTestSvc", spNgTestSvc);
    spNgTestSvc.$inject = ["spBaseService"];
GET 请求示例
spBaseService.getRequest(query, endPoint)
您可以传递支持 HTTP GET 请求的任何查询或端点。例如:
您想获取当前站点下的所有列表
function getAllLists() {
    var query = "/_api/web/lists?$select=Title";
    return spBaseService.getRequest(query);
}
如果您想获取列表的所有项目,那么将是:
function getAllItems() {
    var query = "/_api/web/lists/GetByTitle('List Title')/Items";
    return spBaseService.getRequest(query);
}
如果您想获取所有子站点,那么将是:
function getSubSites() {
    var query = "/_api/Web/Webs";
    return spBaseService.getRequest(query);
}
所以,我通过这些示例想说的是:只需发出任何 GET 请求,您就需要处理查询或端点。
endPoint 参数的使用
有些人可能需要在以下场景中使用 endPoint:
假设您当前的站点是 https://xxx.sharepoint.com (可以是 Host Web 或 App Web)。现在您想对子站点 https://xxx.sharepoint.com/hr 发出 GET, POST, UPDATE 或 DELETE 请求,或者从 App Web 对 Host Web 发出 GET, POST, UPDATE 或 DELETE 请求。在这种情况下,您需要使用 endPoint。
function getSubSites() {
    var endPoint = "https://xxx.sharepoint.com/hr/_api/Web/Webs";
    return spBaseService.getRequest(null, endPoint);
}
POST 请求示例
这适用于添加新对象(列表项、文件、站点、文档等)。
spBaseService.postRequest(data, url, endPoint)
data 是请求体。它会因请求而异。例如,要添加一个子站点,请求体应如下所示:
var data = {
    parameters: {
        __metadata: {
            'type': 'SP.WebInfoCreationInformation'
        },
        Url: "site url",
        Title: "site title",
        Description: "site description",
        Language: 1033,
        UseUniquePermissions: true
    }
};
url 是任何支持 POST 请求的端点。要添加子站点,端点是:
var url = "/_api/web/webinfos/add";
endPoint 的用法可以在 此处 找到。
因此,添加站点的完整 POST 请求是:
function addSubSite() {
    var data = {
        parameters: {
            __metadata: {
                'type': 'SP.WebInfoCreationInformation'
            },
            Url: "site url",
            Title: "site title",
            Description: "site description",
            Language: 1033,
            UseUniquePermissions: true
        }
    };
    var url = "/_api/web/webinfos/add";
    return spBaseService.postRequest(data, url);
}
UPDATE 请求示例
spBaseService.updateRequest(data, url, endPoint);
它与 POST 请求几乎相同。您可以使用此方法更新站点中的任何对象。看看更新特定列表中的项目。
function updateItemById(itemId) {
    var url = "/_api/web/lists/GetByTitle('List Name')/GetItemById(" + itemId + ")";
    var data = {
        __metadata: {
            type: "SP.Data.SpNgListListItem"
        },
        Title: "New sp ng item updated " + Math.random()
    };
    return spBaseService.updateRequest(data, url);
}
请在此处 查看 endPoint 的用法。
DELETE 请求示例
spBaseService.deleteRequest(url, endPoint);
您将使用此方法从站点中删除某些内容。假设我们要删除 ID 等于 5 的项目。
function deleteAnItem() {
    var url = "/_api/web/lists/GetByTitle('List Name')/GetItemById(5)";
    return spBaseService.deleteRequest(url);
}
请在此处 查看 endPoint 的用法。
文件上传示例
spBaseService.fileUploadRequest(data, url, endPoint);
在请求体中,您需要将文件作为 ArrayBuffer 传递。如前所述,此模块还包含一个指令,该指令将帮助您以 ArrayBuffer 格式获取文件。该指令的名称是 customFileChange。用于上传的 HTML 应如下所示:
<input type="file" data-custom-file-change="attachment" /> 
attachment 是模型,它将为您提供 ArrayBuffer 格式的文件。您可以根据需要更改其名称。您将从此模型中获得两个属性,例如 fileName 和 fileAsBuffer。
以下是上传 ID 等于 2 的特定项目的附件的示例:
function uploadAttachment(attachment){
            var url = "/_api/web/lists/GetByTitle('SpNgList')/items(2)/
                       AttachmentFiles/add(FileName='" + attachment.fileName + "')";
            return spBaseService.fileUploadRequest(attachment.fileAsBuffer, url);
        }
请在此处 查看 endPoint 的用法。
处理响应示例
您将从上述所有方法中获得一个 Promise 作为返回值。因此,这与典型的响应处理 Angular 代码相同。例如:
spNgTestSvc.addSubSite()
    .then(function(successResponse) {
        // code after success
    }, function(errorrResponse) {
        //code after error
    });
errorResponse 有两个属性,例如 error 和 status。error 是 SharePoint 端点返回的实际错误对象。
结论
以上就是我当前模块的全部内容。我将尝试在未来的更新中使其变得更好。由于我的源代码是开放的,如果您能收到读者的任何反馈和建议,我将非常高兴。
历史
- 2016 年 7 月 29 日:初始版本


