如何使提交功能在使用 Google Apps 脚本创建并嵌入到 Google 站点中的 Web 表单中工作?

How to make submission function work in a web form that is created using Google Apps Script and embedded in a Google Site?

我想将使用 Google Apps 脚本创建的网站嵌入到 Google 网站。但是,当表单嵌入 Google 网站(如 this.

时,表单中的数据提交按钮将失效

在网络表单中,表单访问者将数据输入到由index.html生成的表单中,并在数据提交后看到result.htmlindex.html中有一个内部的link,用来连接一个header和它的相关内容。当表单应用程序未嵌入任何其他站点时,它可以成功运行。查看the form app,您会发现数据提交按钮可以正常工作。

有人告诉我我错过了什么吗?

MWE

我在 Google Apps 脚本的同一个项目中有四个文件:

  1. index.html 生成表单
  2. JavaScript.html 定义了 index.html
  3. 中使用的函数
  4. result.html 表单提交后显示
  5. code.gsdoGet() 显示表单,并处理提交的数据并由 doPost() 呈现 result.html。此文件中定义的 include() 允许将 JavaScript.html 输入到 index.html

index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <!-- <?!= include("css"); ?> -->
  </head>

  <body onload="addOptions()">   <!--Execute addOptions function immediately after a page has been loaded-->
    <form class="" action="<?!= getScriptUrl(); ?>" method="post" onSubmit="document.getElementById('submit').disabled=true;">
      <div>
        <h1 id="Question">
          Choose either cheesecake or chocolate cake.
        </h1>
          <select id="dropdownList" name="cake" class="form-control"> 
          </select>
      </div>
      <p>
        <div style="width:100px;height:500px;border:1px solid #000;">
          Blank box to scroll down
        </div>
      </p>
      <p>
        Please do not forget what you've answered in the <a href="#Question" target="_self">question<a>
      </p>
      <div class="form-submit">
        <input type="submit" name="" value="Submit">
      </div>
    </form>
  </body>
  <?!= include('JavaScript') ?>
</html>

JavaScript.html

<script>
  function addOptions() {
    /*This will call server-side Apps Script function getAvailableExps and if it is successful, 
    it will pass the return value to function addListValues which will add options to the drop down menu*/
    google.script.run
      .withFailureHandler(onFailure)
      .withSuccessHandler(addListValues)
      .getAvailableExps();
  }

  function addListValues(values) { 
    //Add options to drop down menu using the values of parameter 'values'.     
    for (var i = 0; i < values.length; i++) {
      var option = document.createElement("option");
      option.text = values[i][0];
      option.value = values[i][0];
      var select = document.getElementById("dropdownList");
      select.appendChild(option);
    }
  }

  function onFailure(err) {
    alert('Error: ' + err.message);
  }
</script>

result.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <base />
    <title>Thank you for your order!</title>
    <!-- <?!= include('css'); ?> -->
  </head>
  <body>
    <p>
      Don't forget what you've ordered!
    </p>
  </body>
</html>

code.gs

var sheetID = "............................................";
var inventory_sheet = "Inventory";

function doGet(){
  PropertiesService.getScriptProperties().setProperty("key", "sample");
  return HtmlService.createTemplateFromFile("index").evaluate();
}

function include(filename){
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}

function getScriptUrl() {
  var url = ScriptApp.getService().getUrl();
  Logger.log(url);
  return url;
}

function doPost(e){
  var p = PropertiesService.getScriptProperties();

  if (p.getProperty("key") == "sample") {

    var ss = SpreadsheetApp.openById(sheetID);
    var sh = ss.getSheets()[0];
    sh.appendRow([String(e.parameters.cake)]);

    //update Inventory
    var inventory = ss.getSheetByName(inventory_sheet);
    var row = inventory.createTextFinder(e.parameters.cake).findNext().getRow();
    var range = inventory.getRange(row, 2);
    var data = range.getValue();
    range.setValue(parseInt(data - 1))

    p.deleteProperty("key");
  }

  return HtmlService.createTemplateFromFile("result").evaluate(); 
  
}

function getAvailableExps(){
  var inventory = SpreadsheetApp.openById(sheetID).getSheetByName(inventory_sheet);
  var data =  inventory.getRange(2, 1, 2, 2).getValues();
  var filtered = data.filter(arr =>  arr[1] > 0 || arr[1] != ''); //remove exp to array if quantity is 0 or empty
  return filtered;
}

问题和解决方法:

我认为在你的情况下,你的目标很难用你的展示脚本直接实现。 .

中已经提到了这个原因

当我看到 时,您似乎需要 运行 Google 端的 Web 应用程序。

在这种情况下,我认为可能需要使用变通方法。在这个答案中,为了实现您的目标,我想提出一个解决方法。此解决方法的要点如下。

  • 在您的脚本中,<select id="dropdownList" name="cake" class="form-control"></select> 的值使用表单的 action="<?!= getScriptUrl(); ?>" method="post" 发送到 doPost
  • 在此解决方法中,使用 google.script.run 将值发送到 Google Apps 脚本。并且,在值完全提交后,HTML 正文被 result.html.
  • 覆盖

当这一点反映在你的脚本中,就变成了下面这样。

修改后的脚本:

index.html

请修改index.html如下。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <!-- <?!= include("css"); ?> -->
  </head>
  <body id="body" onload="addOptions()">
    <form id="form">
      <div>
        <h1 id="Question">
          Choose either cheesecake or chocolate cake.
        </h1>
          <select id="dropdownList" name="cake" class="form-control"> 
          </select>
      </div>
      <p>
        <div style="width:100px;height:500px;border:1px solid #000;">
          Blank box to scroll down
        </div>
      </p>
      <p>
        Please do not forget what you've answered in the <a href="#Question" target="_self">question<a>
      </p>
      <div class="form-submit">
        <input type="submit" name="" value="Submit" onclick="sample(this);return false;">
      </div>
    </form>
  </body>
  <?!= include('JavaScript') ?>
</html>

JavaScript.html

请在JavaScript.html中添加以下功能。

function sample(e) {
  const f = document.getElementById("form");
  const obj = { parameters: [...f].reduce((o, g) => (o[g.name] = [g.value], o), {}) };
  google.script.run
    .withSuccessHandler((res) => {
      document.getElementById("body").innerHTML = res;
    })
    .sample(obj);
}
  • 在此示例脚本中,为了直接使用您的 doPost,准备了 obj 的值。请注意这一点。

Code.gs:Google Apps 脚本端

请将以下功能添加到Code.gs。此功能使用您的 doPost.

function sample(e) {
  return doPost(e).getContent();
}

测试:

当此修改反映在您的脚本中并且您的 Web 应用程序嵌入到 Google 站点时,单击提交按钮时,cake 的值将发送到 Google Apps 脚本端并显示 result.html。我以为这种情况可能是你期望的结果。

注:

  • 此修改是一个简单的修改,用于解释解决方法。所以,请根据您的实际情况进行修改。

  • 当您修改 Google Apps 脚本时,请将部署修改为新版本。这样,修改后的脚本就会反映在 Web Apps 中。请注意这一点。

  • 你可以在“Redeploying Web Apps without Changing URL of Web Apps for new IDE”的报告中看到详细信息。

  • 关于Google站点Web Apps的内部link,似乎当Web Apps的while页面被嵌入且滚动条不显示时,内部 link 不起作用。当显示框架的滚动条时,link 起作用。在这种情况下,内部 link 似乎无法同时使用 HTML 和 Javascript。而且,我无法确认错误消息。