【问题标题】:Google Apps Script - Callback for class methods used in webappGoogle Apps 脚本 - webapp 中使用的类方法的回调
【发布时间】:2020-03-12 12:09:35
【问题描述】:

我有一个 GAS,我在我的 webapp 中提交了一个表单。它执行以下操作:

  1. 打开一个包含占位符(格式为##form_field_name##)的模板文档,该占位符对应于表单上的表单域的名称
  2. 复制模板并将其保存到适当的位置
  3. 遍历提交的值并执行body.replaceText('##' + key + '##', val); 将值填充到文档中
  4. 使用body.replaceText('##.*##', ''); 删除任何留空字段的占位符字符串(因为它们当前未与表单一起提交)

我最终得到的文档看起来用户根本没有提交任何数据。我的猜测是这是因为 #4 在 #3 完成之前运行。有没有办法将#4 指定为回调?比如:

body.replaceText('##' + key + '##', val, () => {
    body.replaceText('##.*##', '');
});

这是执行replaceText()ing 的函数的代码:

/**
 * Iterate through obj of keys/values and replace ##key## 
 * with value in doc 
**/
function doFindAndReplace(obj, doc) {
  try {
    //body = doc.getBody();
    var id = doc.getId();
    var _doc = DocumentApp.openById(id);
    var body = _doc.getBody();
    //var doc = _doc;
    //Logger.log(body);
    for (var prop in obj) {
      if(obj.hasOwnProperty(prop)) {
        var val = obj[prop];
        var key = prop.indexOf('intake') === 0 ? prop.toUpperCase() : '';
        //Logger.log(key + ' = ' + val);
        //Logger.log(typeof val);
        body.replaceText('##' + key + '##', val);
        _doc.saveAndClose();
        var _doc2 = DocumentApp.openById(id);
        body = _doc2.getBody();
        body.replaceText('##.*##', '');
      }
    }
  } catch(e) {
    Logger.log('doFindAndReplace() | ' + e);
    errors.push({ 
      fxn: 'doFindAndReplace', 
      msg: e, 
      custom: 'id=' + id
    });
    return false;
  }
  return doc;
}

参数obj 是一个包含提交的表单数据的对象,doc 是对正在其中进行查找和替换的新创建文档的引用。

如果不可能的话,我正在考虑添加一个运行#4 (body.replaceText('##.*##', '');) 的onOpen 触发器。这将要求用户在线时首次打开文档,并且很大一部分用例是离线使用新创建的文档。

谁能建议另一种解决方法?


** **编辑** **
我将我的代码(如上所示)更新为“saveAndClose()”,然后在运行第二个“replaceText()”之前重新打开。我收到以下错误:

文档已关闭,其内容无法更新

我知道,你会认为它会出现在 saveAndClose() 之后。但这是错误所在的行,即使我删除了它之后的其余行,也会发生同样的错误。

如果我按原样删除带有代码的saveAndClose() 行,我会再次遇到原来的问题。

我不认为这和Weird Behaviour with DriveApp.getFileById()是同一个问题


** **编辑 2** **
这是传递给函数的对象的示例:
{
intake_activity_level: "Normal",
intake_assessment_comments: "",
intake_client_addr: "1600 Fake St XXXX, XX 12345",
intake_client_email: "xxx@gmail.com",
intake_client_name: "Dan Tester",
intake_client_phone: "(917) 555-1212", 
intake_consent: "yes", 
intake_consent_owner: "Jim David",
intake_food_intake: "Decreased",
intake_gen_food: "",
intake_gen_health: "sit dolam amet",
intake_gen_meds: "re et sapien et, consectetur rhoncus lacus. Aliqua Vivamus ipsum diam, venenatis a turpis eget, volu",
intake_gen_reasons: "Lorem ipsum",
intake_gen_vaccine: "Yes",
intake_misc_comments: "",
intake_misc_descriptor: "wood",
intake_panting: "Increased",
intake_pet_breed: "Pug",
intake_pet_dob: "8/11/2015",
intake_pet_name: "FLuffy",
intake_pet_sex: "Spayed Female",
intake_pet_species: "Dog",
intake_pet_weight: "140lbs",
intake_sleep: "Increased",
intake_source: "Sally Balls",
intake_stiffness: "Normal",
intake_symptoms: "coughing, belching or gas",
intake_vet: "Urban Vet",
intake_voice: "Increased",
intake_water_intake: "Decreased"
}

可以通过here 访问文档的简化版本。

【问题讨论】:

  • 您的问题可能源于最近与表单提交相关的错误。基本上,存在“幻像”提交,其中表单以某种方式自动提交而没有相应的数据。在 stackoverflow 中搜索相关主题,您应该会找到该问题的各种解决方法。
  • 没有 GAS 正在接收数据。当我删除 body.replaceText('##.*##', ''); 时,文档填充得很好。我只需要一种方法来阻止该行运行,直到上一个 replaceText() 调用完成。
  • GAS 是同步的。你错过了别的东西。你能展示你的完整剧本吗?
  • @Tanaike - 感谢您对此进行调查。是的,var key = prop.indexOf('intake') === 0 ? prop.toUpperCase() 行正在产生所需的结果。没有任何需要的数据被重置为空字符串。带有示例数据的对象以及指向示例文档的链接在我上面的帖子中,位于** EDIT 2 **

标签: google-apps-script web-applications asynccallback


【解决方案1】:
  • 您想使用 obj'##' + key + '##' 替换为 va;body.replaceText('##' + key + '##', val);
  • 您想将##.*## 替换为''body.replaceText('##.*##', '');
  • 您想在所有 body.replaceText('##' + key + '##', val); 运行后运行 body.replaceText('##.*##', '');

如果我的理解是正确的,那么这个答案呢?

在您当前的脚本中,body.replaceText('##.*##', ''); 被放入 for 循环中。这样,只使用了intake_activity_level: "Normal",,不使用其他对象。在这种情况下,在第一个body.replaceText('##' + key + '##', val); 运行后,所有##key## 值都被body.replaceText('##.*##', ''); 删除。我认为这可能是您的问题的原因。

修改脚本:

当你的脚本被修改时,请进行如下修改。

从:
for (var prop in obj) {
  if(obj.hasOwnProperty(prop)) {
    var val = obj[prop];
    var key = prop.indexOf('intake') === 0 ? prop.toUpperCase() : '';
    //Logger.log(key + ' = ' + val);
    //Logger.log(typeof val);
    body.replaceText('##' + key + '##', val);
    _doc.saveAndClose();
    var _doc2 = DocumentApp.openById(id);
    body = _doc2.getBody();
    body.replaceText('##.*##', '');
  }
}
到:
for (var prop in obj) {
  if(obj.hasOwnProperty(prop)) {
    var val = obj[prop];
    var key = prop.indexOf('intake') === 0 ? prop.toUpperCase() : '';
    body.replaceText('##' + key + '##', val);
  }
}
body.replaceText('##.*##', '');
  • 在这个修改中,首先body.replaceText('##' + key + '##', val);在for循环中运行。然后,body.replaceText('##.*##', ''); 在 for 循环的外部运行。

注意:

  • 如果需要saveAndClose(),将doc.saveAndClose()放在body.replaceText('##.*##', '');之后怎么样?

【讨论】:

  • 呜呜呜呜!!我不敢相信我没有发现第二个replaceText() 在循环内!显然,它修复了它。谢谢!!
  • @Daveh0 感谢您的回复和测试。我很高兴你的问题得到了解决。也谢谢你。
猜你喜欢
  • 2021-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多