使用 SharePoint JavaScript API 处理 SharePoint 数据

这是关于开发 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 及其调用按钮

  1. 确认是否已完成本系列中首篇教程提及的下列步骤:

    打开项目根目录中的文件“/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>
    

    然后,在文件中搜索其他任何也会加载这一个或两个文件的标记,并删除多余的标记。 保存并关闭文件。

  2. 在“解决方案资源管理器”的“脚本”节点中,可能已有 Add-in.js 文件。 如果没有 Add-in.js 文件,而有 App.js 文件,请右键单击“App.js”,再将它重命名为“Add-in.js”。 如果 Add-in.js 或 App.js 文件都没有,请按照以下步骤创建一个:

    1. 右键单击“脚本”节点,再依次选择“添加”>“新项”>“Web”

    2. 选择“JavaScript 文件”,再将它命名为“Add-in.js”

    3. 更新 aspx 页面中的代码以引用正确的 JS 文件:将其从:

      <script type="text/javascript" src="../Scripts/App.js"></script>
      

      更改为

      <script type="text/javascript" src="../Scripts/Add-in.js"></script>
      
  3. 打开 Add-in.js,并删除其中的内容(若有)。

  4. 将以下代码行添加到此文件。

    '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”字段设置为“已完成”的列表项。
  5. 为了最大限度地减少客户端浏览器和 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);
    }
    
  6. 如果这些代码行已发送到服务器并在其中执行,则会创建一组列表项,但脚本必须将相应集合向下传递到客户端。 为此,需要调用 SP.ClientContext.load 函数。因此,在方法结尾处添加以下代码行。

    clientContext.load(completedItems);
    
  7. 添加对 executeQueryAsync 的调用。 此方法有两个参数,两者都是回调函数。 如果服务器成功执行批处理中的所有命令,那么第一个函数运行。 如果服务器出于某种原因而无法执行,那么第二个函数运行。 将在后续步骤中创建这两个函数。 在方法结尾处添加以下代码。

    clientContext.executeQueryAsync(deleteCompletedItems, onGetCompletedItemsFail);
    
  8. 最后,在方法结尾处添加以下代码。。

    return false;
    

    通过将 false 返回给将调用函数的 ASP.NET 按钮,可以取消 ASP.NET 按钮的默认行为(即重新加载网页)。 重新加载网页会导致 Add-in.js 文件重新加载。 这反过来会重新初始化 clientContext 对象。

    如果此重新加载在 executeQueryAsync 发送请求和 SharePoint 服务器发送回响应期间完成,原始 clientContext 对象将不再存在,导致响应无法处理。 函数将中止,既不执行成功回调函数,也不执行失败回调函数。 (具体行为可能因浏览器而异。)

  9. 将以下函数 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);
    }
    
  10. 将以下函数 onDeleteCompletedItemsSuccess 添加到文件中。 这是在成功删除已完成项(或列表中没有任何已完成项)时要运行的函数。

    代码行 location.reload(true); 会导致页面从服务器重新加载。 这是一种便捷做法,因为除非刷新页面,否则页面上的列表视图 Web 部件仍会显示已完成项。 这还会重新加载 Add-in.js 文件,但并不会导致问题发生,因为这样做并不会以任何方式中断正在运行的 JavaScript 函数。

    function onDeleteCompletedItemsSuccess() {
      alert('Completed orientations have been deleted.');
      location.reload(true);
    }
    
  11. 将以下两个失败回调函数添加到文件中。

    // 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());
    }
    
  12. 打开 default.aspx 文件并查找 ID 为 PlaceHolderMainasp:Content 元素。

  13. 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>
    
  14. 在 Visual Studio 中重新生成项目。

  15. 为了在测试加载项时尽量避免必须将列表项的“入职培训阶段”手动设置为“已完成”,请打开列表实例 NewEmployeesInSeattleelements.xml 文件(不是列表模板 NewEmployeeOrientationelements.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>
    

运行并测试加载项

  1. 在调试时 Visual Studio 使用的浏览器中启用弹出窗口。

  2. 按 F5 键部署并运行加载项。 Visual Studio 在测试 SharePoint 网站上临时安装并立即运行此加载项。

  3. 此时,加载项的主页打开,列表中有一个或多个项的“入职培训阶段”为“已完成”

    图 1. 清除已完成项目之前的列表

    “西雅图的新员工”列表包含“培训阶段”列,有两个项目设置为“已完成”。列表下方有一个标记为“清除已完成项目”的按钮。

  4. 在加载项的起始页加载后,选择“清除已完成的项”按钮。 如果操作成功(未看到任何失败消息),则所有“已完成”项都已删除,将看到显示“已删除已完成入职培训的员工”的弹出窗口。

  5. 关闭弹出窗口。 此时,页面重新加载,列表视图 Web 部件中不再有“已完成”项。

    图 2. 清除已完成项目之后的列表

    比之前少两项的“西雅图新员工”列表,并且没有将“入职培训阶段”设置为“已完成”的项。

  6. 若要结束调试会话,请关闭浏览器窗口或停止在 Visual Studio 中进行调试。 每次按 F5,Visual Studio 都会撤回旧版加载项并安装最新版本。

  7. 将在其他文章中使用此加载项和 Visual Studio 解决方案,因此最好在使用一段时间后,再最后撤回一次加载项。 在“解决方案资源管理器”中,右键单击此项目,再选择“撤回”

后续步骤

本系列的下一篇文章通过加载项 Web 中的 JavaScript 处理主机 Web 数据将介绍如何向加载项 Web 上的页面添加 JavaScript,从而处理主机 Web 上的 SharePoint 数据。