尝试从电子表格中获取值时获取 "undefined"

Getting "undefined" when trying to get values from spreadsheet

当我尝试从电子表格的单元格中获取值时,出现 "undefined" 错误。问题是,如果我对不同的单元格执行相同的命令,我将获得该单元格中的值。这 2 个单元之间的唯一区别是产生值的方式。

单元格中正确显示的值是直接从与该电子表格关联的 Google 表单生成的。调用时不显示的值是从我在 Google 表单中创建的脚本生成的。

表单脚本(在表单提交时触发):

// This code will set the edit form url as the value at cell "C2".

function assignEditUrls() {
    var form = FormApp.getActiveForm();
    var ss = SpreadsheetApp.openById("my-spreadsheet-id")
    var sheet = ss.getSheets()[0];

    var urlCol = 3; // column number where URL's should be populated; A = 1, B = 2 etc
    var formResponses = form.getResponses();

    for (var i = 0; i < formResponses.length; i++) {
        var resultUrl = formResponses[i].getEditResponseUrl();
        sheet.getRange(2 + i, urlCol).setValue(resultUrl); 
    } 
    SpreadsheetApp.flush();
 }

Table(改为HTML)

<table>
    <tr> <!-- Row 1 -->
        <td>Timestamp</td> <!-- A1 -->
        <td>Name</td> <!-- B1 -->
        <td>Edit form URL</td> <!-- C1 -->
    </tr>
    <tr> <!-- Row 2 -->
        <td>5/26/2015 14:04:09</td> <!-- A2: this value came from the form submittion-->
        <td>Jones, Donna</td> <!-- B2: this value came from the form submittion-->
        <td>https://docs.google.com/forms/d/1-FeW-mXh_8g/viewform?edit2=2_ABaOh9</td> <!-- C2: this value came from the the script in the form -->
    </tr>
</table>

电子表格中的脚本(在表单提交时触发)

function onFormSubmit(e) {

    // This script will get the values from different cells in the spreadsheet 
    // and will send them into an email.

    var name = e.range.getValues()[0][1]; // This will get the value from cell "B2".
    var editFormURL = e.range.getValues()[0][2]; // This will get the value from cell "C2".

    var email = 'my-email@university.edu';
    var subject = "Here goes the email subject."
    var message = 'This is the body of the email and includes'
                  + 'the value from cell "B2" <b>'
                  + name + '</b>. This value is retrieved correctly.' 
                  + '<br>But the value from cell "C2" <b>'+ editFormURL
                  + '</b> show as "undefined".';

    MailApp.sendEmail(email, subject, message, {htmlBody: message});
}

电子邮件如下所示:

发件人:my-email@university.edu

主题:这是电子邮件主题。

正文:

这是电子邮件的正文,包括单元格 "B2" Jones, Donna 中的值。此值已正确检索。

但单元格 "C2" 未定义 的值显示为 "undefined"。

问题:

我做错了什么?

您很可能遇到了竞争条件。

  1. 用户提交了一个表单。这是我们的主要活动。

  2. 提交表单后,将触发与事件关联的所有触发器。

    • assignEditUrls() 在表单脚本中,并且

    • onFormSubmit() 在电子表格脚本中。

    如果您为此事件设置了其他脚本,它们也会触发。这里的复杂之处在于,所有这些触发器都被 独立地 触发,或多或少同时触发,但没有保证执行顺序。电子表格触发器可能 运行 在表单触发器之前!所以这是一个问题。

每个触发器都将以特定于其定义的格式接收事件信息。 (参见 Event Objects.) Since C2 is not actually part of the form submission, it won't be in the event object received by the spreadsheet function. That's your second problem, but since you know the offset of the value relative to the form input, you can use range.offset() 获取它。

另一个问题与文档和电子表格的共享方式有关;每个单独的脚本调用都会收到它自己的电子表格副本,该副本与其他副本同步......最终。一个脚本对电子表格所做的更改不会立即对所有其他用户可见。这会产生三个问题。

怎么办?

您可以尝试协调两个相关触发器函数的操作。如果它们在同一个脚本中,锁定服务可以提供帮助。

您可以只用一个触发器函数来执行这两个操作。

或者您可以让电子表格功能容忍任何延迟,方法是让它等待 C2 被填充。这段代码可以做到这一点...

...
var editFormURL = null;
var loop = 0;
while (!editFormURL) {
  editFormURL = e.range.offset(0,2).getValue(); // This will get the value from cell "C2".
  if (!editFormURL) {
    // Not ready yet, should we wait?
    if (loop++ < 10) {
      Utilities.sleep(2000); // sleep 2 seconds
    }
    else throw new Error( 'Gave up waiting.' );
  }
}

// If the script gets here, then it has retrieved a value for editFormURL.
...

一个额外的问题:由于您使用 getValues(),复数 s,您正在检索二维信息数组。您没有看到问题,因为当您将这些值视为字符串时,javascript 解释器 强制 将数组转换为您希望的字符串。但这仍然是一个问题-如果您想要单个值,请使用 getValue().

获取正确的行,然后使用 URL:

对列进行硬编码
var ss = SpreadsheetApp.openById("my-spreadsheet-id")
var sheet = ss.getSheets()[0];

var rowForLookup = e.range.getRow();
var columnOfUrl = 24; //Column X
var theUrl = sheet.getRange(rowForLookup, columnOfUrl).getValue();

所以这段代码是我在实施你的建议后最终得到的。感谢 Sandy Good 和 Mogsdad。

function onFormSubmit(e) {

    Logger.log("Event Range: " + e.range.getA1Notation());

    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getSheets()[0];

    var startRow = e.range.getRow();
    var startCol = 1;
    var numRows = 1;
    var numColumns = sheet.getLastColumn();

    var dataRange = sheet.getRange(startRow, startCol, numRows, numColumns);
    var data = dataRange.getValues();

    Logger.log("Data Range: " + dataRange.getA1Notation());


    for (var i = 0; i < data.length; ++i) {
        var column = data[i];
        var name = column[4];

        var editFormURL = null;
        var loop = 0;

        while (!editFormURL) {
            editFormURL = column[23];
            if (!editFormURL) { 
                // Not ready yet, should we wait?
                if (loop++ < 10) {
                    Utilities.sleep(3000); // sleep 2 second
                }
                else throw new Error( 'Gave up waiting.' );
            }
        }    

        var email = 'my-email@university.edu';
        var subject = "Subject here";
        var message = 'Some text about ' + name + '.' +
                      '<br><br>Please view this link: ' + 
                      + editFormURL;

        MailApp.sendEmail(email, subject, message, {htmlBody: message});
    }
}