这是关于开发 SharePoint 托管的 SharePoint 外接程序的基础知识系列文章中的第 10 篇文章。你应该首先熟悉SharePoint 外接程序以及本系列中之前的文章,可在开始创建 SharePoint 托管的 SharePoint 外接程序 | 后续步骤中找到相关内容。
注意
如果已完成有关 SharePoint 托管加载项的本系列文章之一,便已生成 Visual Studio 解决方案,可以在继续阅读本主题的过程中使用。 也可以从 SharePoint_SP-hosted_Add Ins_Tutorials 下载存储库,再打开 BeforeJSOM.sln 文件。
尽管 SharePoint 托管的 SharePoint 外接程序不得包含服务器端代码,但仍可以使用 JavaScript 和 SharePoint JavaScript 客户端对象模型库,在 SharePoint 托管的 SharePoint 外接程序中添加业务逻辑以及与 SharePoint 组件的运行时交互。 将此称为“JSOM”。 请注意结尾处的“M”。 请勿将此与 JSON(JavaScript 对象表示法)相混淆。 本文将介绍如何使用 JavaScript 对象模型在“西雅图新员工”列表中查找并删除旧项。
创建 JavaScript 及其调用按钮
确认是否已完成本系列中首篇教程提及的下列步骤:
打开项目根目录中的文件“/Pages/Default.aspx”。 其中,这一生成的文件加载 SharePoint 上托管的一个或两个脚本:sp.runtime.js 和 sp.js。 加载这些文件的标记位于文件顶部附近的“内容”控件(ID 为
PlaceHolderAdditionalPageHead)中。 此标记因所使用的 Microsoft Visual Studio 的 Office 开发人员工具版本而异。这一系列教程要求使用普通的 HTML
<script>标记(而非<SharePoint:ScriptLink>标记)同时加载这两个文件。 请确保PlaceHolderAdditionalPageHead控件中<meta name="WebPartPageExpansion" content="full" />代码行的正上方有下列代码行:<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script> <script type="text/javascript" src="/_layouts/15/sp.js"></script>然后,在文件中搜索其他任何也会加载这一个或两个文件的标记,并删除多余的标记。 保存并关闭文件。
在“解决方案资源管理器”的“脚本”节点中,可能已有 Add-in.js 文件。 如果没有 Add-in.js 文件,而有 App.js 文件,请右键单击“App.js”,再将它重命名为“Add-in.js”。 如果 Add-in.js 或 App.js 文件都没有,请按照以下步骤创建一个:
右键单击“脚本”节点,再依次选择“添加”>“新项”>“Web”。
选择“JavaScript 文件”,再将它命名为“Add-in.js”。
更新 aspx 页面中的代码以引用正确的 JS 文件:将其从:
<script type="text/javascript" src="../Scripts/App.js"></script>更改为
<script type="text/javascript" src="../Scripts/Add-in.js"></script>
打开 Add-in.js,并删除其中的内容(若有)。
将以下代码行添加到此文件。
'use strict'; var clientContext = SP.ClientContext.get_current(); var employeeList = clientContext.get_web().get_lists().getByTitle('New Employees In Seattle'); var completedItems;关于此代码,请注意以下几点:
'use strict';代码行可确保浏览器中的 JavaScript 运行时在检测到无意间采取的特定 JavaScript 错误做法时抛出异常。clientContext变量包含引用 SharePoint 网站的SP.ClientContext对象。 所有 JSOM 代码首先创建或获取对此类型对象的引用。employeeList变量保留对列表实例“西雅图新员工”的引用。completedItems变量保留脚本将删除的列表项,即“OrientationStage”字段设置为“已完成”的列表项。
为了最大限度地减少客户端浏览器和 SharePoint 服务器之间的消息数,JSOM 使用批量系统。 实际上,只有一个函数
SP.ClientContext.executeQueryAsync将消息发送到服务器(并接收回复)。两次调用
executeQueryAsync间隔期间发生的 JSOM API 调用将在下次调用executeQueryAsync时捆绑起来,并批量发送到服务器。 不过,无法调用 JSOM 对象的方法,除非此对象已向下传递到上一次executeQueryAsync调用中的客户端。脚本将调用每个已完成列表项的
SP.ListItem.deleteObject方法。因此,它需要调用executeQueryAsync两次:一次是为了获取已完成列表项的集合,另一次是为了批处理deleteObject调用,并将它们发送到服务器以供执行。首先,创建用于从服务器获取列表项的方法。 将以下代码添加到文件中。
function purgeCompletedItems() { var camlQuery = new SP.CamlQuery(); camlQuery.set_viewXml( '<View><Query><Where><Eq>' + '<FieldRef Name=\'OrientationStage\'/><Value Type=\'Choice\'>Completed</Value>' + '</Eq></Where></Query></View>'); completedItems = employeeList.getItems(camlQuery); }如果这些代码行已发送到服务器并在其中执行,则会创建一组列表项,但脚本必须将相应集合向下传递到客户端。 为此,需要调用
SP.ClientContext.load函数。因此,在方法结尾处添加以下代码行。clientContext.load(completedItems);添加对
executeQueryAsync的调用。 此方法有两个参数,两者都是回调函数。 如果服务器成功执行批处理中的所有命令,那么第一个函数运行。 如果服务器出于某种原因而无法执行,那么第二个函数运行。 将在后续步骤中创建这两个函数。 在方法结尾处添加以下代码。clientContext.executeQueryAsync(deleteCompletedItems, onGetCompletedItemsFail);最后,在方法结尾处添加以下代码。。
return false;通过将
false返回给将调用函数的 ASP.NET 按钮,可以取消 ASP.NET 按钮的默认行为(即重新加载网页)。 重新加载网页会导致 Add-in.js 文件重新加载。 这反过来会重新初始化clientContext对象。如果此重新加载在
executeQueryAsync发送请求和 SharePoint 服务器发送回响应期间完成,原始clientContext对象将不再存在,导致响应无法处理。 函数将中止,既不执行成功回调函数,也不执行失败回调函数。 (具体行为可能因浏览器而异。)将以下函数
deleteCompletedItems添加到文件中。 这是purgeCompletedItems函数成功时要运行的函数。 关于此代码,请注意以下几点:SP.ListItem.get_id方法将返回列表项的 ID。 数组中的每个项都是SP.ListItem对象。SP.List.getItemById方法返回具有指定 ID 的SP.ListItem对象。- 调用
executeQueryAsync时,SP.ListItem.deleteObject方法将标记服务器上要删除的列表项。 必须先将集合中的列表项从服务器向下发送到数组,然后才能删除它们。 如果脚本在while循环中直接调用每个列表项的deleteObject方法,那么 JavaScript 会抛出错误,指出虽正在进行枚举,但也在更改集合的长度。
错误消息并不是真正意义上的错误消息,因为只有在捆绑
deleteObject调用并将它们发送到服务器时,列表项才会从任何内容中删除,但 JSOM 旨在模拟服务器上抛出的异常(即在枚举集合时,代码不得更改集合大小)。 不过,数组的大小是固定的。因此,对数组的项调用deleteObject会从列表中删除列表项,但不会更改数组大小。function deleteCompletedItems() { var itemArray = new Array(); var listItemEnumerator = completedItems.getEnumerator(); while (listItemEnumerator.moveNext()) { var item = listItemEnumerator.get_current(); itemArray.push(item); } var i; for (i = 0; i < itemArray.length; i++) { itemArray[i].deleteObject(); } clientContext.executeQueryAsync(onDeleteCompletedItemsSuccess, onDeleteCompletedItemsFail); }将以下函数
onDeleteCompletedItemsSuccess添加到文件中。 这是在成功删除已完成项(或列表中没有任何已完成项)时要运行的函数。代码行
location.reload(true);会导致页面从服务器重新加载。 这是一种便捷做法,因为除非刷新页面,否则页面上的列表视图 Web 部件仍会显示已完成项。 这还会重新加载 Add-in.js 文件,但并不会导致问题发生,因为这样做并不会以任何方式中断正在运行的 JavaScript 函数。function onDeleteCompletedItemsSuccess() { alert('Completed orientations have been deleted.'); location.reload(true); }将以下两个失败回调函数添加到文件中。
// Failure callbacks function onGetCompletedItemsFail(sender, args) { alert('Unable to get completed items. Error:' + args.get_message() + '\n' + args.get_stackTrace()); } function onDeleteCompletedItemsFail(sender, args) { alert('Unable to delete completed items. Error:' + args.get_message() + '\n' + args.get_stackTrace()); }打开 default.aspx 文件并查找 ID 为
PlaceHolderMain的asp:Content元素。在
WebPartPages:WebPartZone元素和两个asp:Hyperlink元素中的第一个元素之间添加以下标记。OnClientClick处理程序的值为return purgeCompletedItems(),而不只是purgeCompletedItems()。 函数返回的false指示 ASP.NET 不要重新加载页面。<p><asp:Button runat="server" OnClientClick="return purgeCompletedItems()" ID="purgecompleteditemsbutton" Text="Purge Completed Items" /></p>在 Visual Studio 中重新生成项目。
为了在测试加载项时尽量避免必须将列表项的“入职培训阶段”手动设置为“已完成”,请打开列表实例 NewEmployeesInSeattle 的 elements.xml 文件(不是列表模板 NewEmployeeOrientation 的 elements.xml),并添加标记
<Field Name="OrientationStage">Completed</Field>作为一个或多个Row元素的最后一个子项。下面是
Rows元素的示例。<Rows> <Row> <Field Name="Title">Tom Higginbotham</Field> <Field Name="Division">Manufacturing</Field> <Field Name="OrientationStage">Completed</Field> </Row> <Row> <Field Name="Title">Satomi Hayakawa</Field> <Field Name="OrientationStage">Completed</Field> </Row> <Row> <Field Name="Title">Cassi Hicks</Field> </Row> <Row> <Field Name="Title">Lertchai Treetawatchaiwong</Field> </Row> </Rows>
运行并测试加载项
在调试时 Visual Studio 使用的浏览器中启用弹出窗口。
按 F5 键部署并运行加载项。 Visual Studio 在测试 SharePoint 网站上临时安装并立即运行此加载项。
此时,加载项的主页打开,列表中有一个或多个项的“入职培训阶段”为“已完成”。
图 1. 清除已完成项目之前的列表

在加载项的起始页加载后,选择“清除已完成的项”按钮。 如果操作成功(未看到任何失败消息),则所有“已完成”项都已删除,将看到显示“已删除已完成入职培训的员工”的弹出窗口。
关闭弹出窗口。 此时,页面重新加载,列表视图 Web 部件中不再有“已完成”项。
图 2. 清除已完成项目之后的列表

若要结束调试会话,请关闭浏览器窗口或停止在 Visual Studio 中进行调试。 每次按 F5,Visual Studio 都会撤回旧版加载项并安装最新版本。
将在其他文章中使用此加载项和 Visual Studio 解决方案,因此最好在使用一段时间后,再最后撤回一次加载项。 在“解决方案资源管理器”中,右键单击此项目,再选择“撤回”。
后续步骤
本系列的下一篇文章通过加载项 Web 中的 JavaScript 处理主机 Web 数据将介绍如何向加载项 Web 上的页面添加 JavaScript,从而处理主机 Web 上的 SharePoint 数据。