SharePoint 列在成功调用 JSOM update() 后不更新

SharePoint Columns Don't Update After Successful JSOM update() call

我有一个将项目从标准日历列表复制到第二个标准日历列表的工作流。但是副本包含的任何给定日历项目的详细信息都少于原件。这工作得很好,除了 Start TimeEnd Time 字段在 UTC 时间被复制,我们需要这些时间显示在用户的本地时区(我们在世界各地都有员工,所以它可以'不是静态调整)。我知道 SharePoint 将所有 Dates/Times 存储为 UTC,我知道为什么。

我对这个问题的解决方案是(在主日历中)创建两个隐藏的 Date/Time 列,我将用 EventDate 和 [=15= 中的 dates/times 填充它们] 日历列(UTC 值),但这些新值将使用 SharePoint Client Side Object Model (using JS) 针对时区偏移进行更正。然后我的工作流程会将这些更正后的 dates/times 复制到第二个日历。

以下代码似乎有效。列表项的每次迭代都会调用我的成功处理程序,并且我记录的输出显示所有正确的值。但是,代码运行后,代码本应在每个项目上 updated/set 的两个日期字段仍为空白。

<script src="/_layouts/15/sp.runtime.js"></script> 
<script src="/_layouts/15/sp.js"></script> 
<script>
var siteUrl = "https://duckcreek.sharepoint.com/sites/DCU";

function loadListItems(siteUrl) {
  var ctx = new SP.ClientContext(siteUrl);
  var oList = ctx.get_web().get_lists().getByTitle("Master Calendar");
  var camlQuery = new SP.CamlQuery();
  this.collListItem = oList.getItems(camlQuery);

  // EventDate and EndDate are the pre-defined fields (from the Event  
  // content type) that represent the event start and end date / times
  // CorrectedStartDateTime and CorrectedEndDateTime are pre-existing 
  // Date / Time fields in the list.
  ctx.load(collListItem,
    "Include(Id, DisplayName, EventDate, EndDate, CorrectedStartDateTime, CorrectedEndDateTime)");
  ctx.executeQueryAsync(
    Function.createDelegate(this, this.onLoadListItemsSucceeded),
    Function.createDelegate(this, this.onLoadListItemsFailed));
}

function onLoadListItemsSucceeded(sender, args) {
  var ctx = new SP.ClientContext(siteUrl);
  var oList = ctx.get_web().get_lists().getByTitle("Master Calendar");
  var listItemInfo = "";
  var listItemEnumerator = collListItem.getEnumerator();

  while (listItemEnumerator.moveNext()) {
    // List is loaded. Enumerate the list items
    let oListItem = listItemEnumerator.get_current();

    // Get the Calendar item Start and End dates as stored in SharePoint (UTC)
    let startDateString = oListItem.get_item("EventDate").toString();
    let endDateString = oListItem.get_item("EndDate").toString();

    // Get the GMT time zone offset
    let startDateOffsetHours = parseInt(startDateString.split("GMT-")[1]) / 100; 
    let endDateOffsetHours = parseInt(endDateString.split("GMT-")[1]) / 100; 

    // Create new dates that are the same as the originals
    let resultStartDate = new Date(startDateString);
    let resultEndDate = new Date(endDateString);

    // Adjust the new dates to be correct for the local time zone based on the UTC offset
    resultStartDate.setHours(resultStartDate.getHours() + startDateOffsetHours);
    resultEndDate.setHours(resultEndDate.getHours() + endDateOffsetHours);

    // Update the two placeholder fields in the current list item with the corrected dates
    oListItem.set_item("CorrectedStartDateTime", resultStartDate);
    oListItem.set_item("CorrectedEndDateTime", resultEndDate);

    // Update SharePoint
    oListItem.update();
    ctx.executeQueryAsync(
      Function.createDelegate(this, this.onSetCorrectDateTimesSucceeded),
      Function.createDelegate(this, this.onSetCorrectDateTimesFailed)
    );

    // This is just for diagnostics, but it does show the correct data.
    // And since we are using .get_item() here, it would seem that we
    // are pulling the correct data out of SharePoint, but the two "Corrected"
    // fields remain empty after this function completes successfully.
    listItemInfo += "\nDisplay name: " + oListItem.get_displayName() +
      "\n\tEventDate: " + oListItem.get_item("EventDate") +
      "\n\tEndDate: " + oListItem.get_item("EndDate") +
      "\n\t\tCorrectedStartDateTime: " + oListItem.get_item("CorrectedStartDateTime") +
      "\n\t\tCorrectedEndDateTime: " + oListItem.get_item("CorrectedEndDateTime") +
      "\n--------------------------------------------------------------------------------";
  }
  console.log(listItemInfo.toString());
}

function onLoadListItemsFailed(sender, args) {
  console.log("Request failed!" + args.get_message() + "\n" + args.get_stackTrace());
}

function onSetCorrectDateTimesSucceeded() {
  console.log("Item updated!");
}

function onSetCorrectDateTimesFailed(sender, args) {
  console.log("Request failed!" + args.get_message() + "\n" + args.get_stackTrace());
}

loadListItems(siteUrl); 

</script>​​​

而且,这是代码生成的记录之一(它实际上为第一个日历上的每个项目生成了以下一个记录):

Display name: NEW TEST
    EventDate: Mon Dec 31 2018 19:00:00 GMT-0500 (Eastern Standard Time)
    EndDate: Tue Jan 01 2019 18:59:00 GMT-0500 (Eastern Standard Time)
        CorrectedStartDateTime: Tue Jan 01 2019 00:00:00 GMT-0500 (Eastern Standard Time)
        CorrectedEndDateTime: Tue Jan 01 2019 23:59:00 GMT-0500 (Eastern Standard Time)
--------------------------------------------------------------------------------

但是,日历项不会更新两个 "corrected" 字段:

简单回答

您在 onLoadListItemsSucceeded 函数中重新创建了 SP.ClientContext,因此实际上并没有为原始列表项调用更新。将其保存在变量中并重新使用它。

完整代码

<script src="/_layouts/15/sp.runtime.js"></script> 
<script src="/_layouts/15/sp.js"></script> 
<script>
var siteUrl = "https://duckcreek.sharepoint.com/sites/DCU";
var ctx;

function loadListItems(siteUrl) {
  ctx = new SP.ClientContext(siteUrl);
  var oList = ctx.get_web().get_lists().getByTitle("Master Calendar");
  var camlQuery = new SP.CamlQuery();
  this.collListItem = oList.getItems(camlQuery);

  // EventDate and EndDate are the pre-defined fields (from the Event  
  // content type) that represent the event start and end date / times
  // CorrectedStartDateTime and CorrectedEndDateTime are pre-existing 
  // Date / Time fields in the list.
  ctx.load(collListItem,
    "Include(Id, DisplayName, EventDate, EndDate, CorrectedStartDateTime, CorrectedEndDateTime)");
  ctx.executeQueryAsync(
    Function.createDelegate(this, this.onLoadListItemsSucceeded),
    Function.createDelegate(this, this.onLoadListItemsFailed));
}

function onLoadListItemsSucceeded(sender, args) {
  var oList = ctx.get_web().get_lists().getByTitle("Master Calendar");
  var listItemInfo = "";
  var listItemEnumerator = collListItem.getEnumerator();

  while (listItemEnumerator.moveNext()) {
    // List is loaded. Enumerate the list items
    let oListItem = listItemEnumerator.get_current();

    // Get the Calendar item Start and End dates as stored in SharePoint (UTC)
    let startDateString = oListItem.get_item("EventDate").toString();
    let endDateString = oListItem.get_item("EndDate").toString();

    // Get the GMT time zone offset
    let startDateOffsetHours = parseInt(startDateString.split("GMT-")[1]) / 100; 
    let endDateOffsetHours = parseInt(endDateString.split("GMT-")[1]) / 100; 

    // Create new dates that are the same as the originals
    let resultStartDate = new Date(startDateString);
    let resultEndDate = new Date(endDateString);

    // Adjust the new dates to be correct for the local time zone based on the UTC offset
    resultStartDate.setHours(resultStartDate.getHours() + startDateOffsetHours);
    resultEndDate.setHours(resultEndDate.getHours() + endDateOffsetHours);

    // Update the two placeholder fields in the current list item with the corrected dates
    oListItem.set_item("CorrectedStartDateTime", resultStartDate);
    oListItem.set_item("CorrectedEndDateTime", resultEndDate);

    // Update SharePoint
    oListItem.update();
    ctx.executeQueryAsync(
      Function.createDelegate(this, this.onSetCorrectDateTimesSucceeded),
      Function.createDelegate(this, this.onSetCorrectDateTimesFailed)
    );

    // This is just for diagnostics, but it does show the correct data.
    // And since we are using .get_item() here, it would seem that we
    // are pulling the correct data out of SharePoint, but the two "Corrected"
    // fields remain empty after this function completes successfully.
    listItemInfo += "\nDisplay name: " + oListItem.get_displayName() +
      "\n\tEventDate: " + oListItem.get_item("EventDate") +
      "\n\tEndDate: " + oListItem.get_item("EndDate") +
      "\n\t\tCorrectedStartDateTime: " + oListItem.get_item("CorrectedStartDateTime") +
      "\n\t\tCorrectedEndDateTime: " + oListItem.get_item("CorrectedEndDateTime") +
      "\n--------------------------------------------------------------------------------";
  }
  console.log(listItemInfo.toString());
}

function onLoadListItemsFailed(sender, args) {
  console.log("Request failed!" + args.get_message() + "\n" + args.get_stackTrace());
}

function onSetCorrectDateTimesSucceeded() {
  console.log("Item updated!");
}

function onSetCorrectDateTimesFailed(sender, args) {
  console.log("Request failed!" + args.get_message() + "\n" + args.get_stackTrace());
}

loadListItems(siteUrl); 

</script>​​​

补充说明

  • 时区偏移量可以是负数 (-) 或正数 (+),因此这些行可能不完整

    // Get the GMT time zone offset
    let startDateOffsetHours = parseInt(startDateString.split("GMT-")[1]) / 100; 
    let endDateOffsetHours = parseInt(endDateString.split("GMT-")[1]) / 100;