Pass URL parameter into Web App script

2020-03-06 06:33发布

问题:

This problem has me wanting to pull my hair out. I am trying to pass a URL parameter to Google Apps Script containing the row ID (from a spreadsheet) for the data I'm wanting to present. My parameter is story. However, I'm getting all sorts of errors no matter what I try. The latest being:

TypeError: Cannot read property "parameter" from undefined. (line 2, file "Code", project "singleStory")

Below are my Code.gs and Index.html files (The project is not complete. This is just where I'm at so far.)

Code.gs

function doGet(e) {
    var i = e.parameter.story;
    return HtmlService
      .createTemplateFromFile('Index')
      .evaluate()
      .setSandboxMode(HtmlService.SandboxMode.IFRAME);

 function getData() {
 return SpreadsheetApp
      .openById("1Z582cnr03fkLC7xCca4pcj7QwDtSCS4KGneyFKMgdyo")
      .getSheetByName("StoryTopics")
      .getDataRange()
      .getValues();
 }
}

Index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <? var data = doGet(); ?>

<div id="container">
<div id="header">
<div id="topicname">
    <?= data[i][0] ?>
</div>
<div id="todaysdate">
<p>As of: <?= new Date() ?></p>
</div>
<div id="topictype">
<?= data[i][1] ?>
</div>
<div id="locale">
<?= data[i][2] ?>
</div>
</div>
<div id="contact_container">
<div id="subheader">
</div>
<div id="contact_name">
<?= data[i][3] ?>
</div>
<div id="contact_title">
<?= data[i][4] ?>, <?= data[i][5] ?>
</div>
<div id="contact_email">
<?= data[i][6] ?>
</div>
<div id="contact_phone">
<?= data[i][7] ?>
</div>
</div>
<div id="action_container">
<div id="subheader">
</div>
<table id="action_table">
<tr>
<td>
Date:
</td>
<td>
Type:
</td>
<td>
Description:
</td>
</tr>
</table>
</div>
<div id="story_container">
<div id="story_title">
</div>
<div id="story_content">
</div>
</div>
</div>
</body>
</html>

The URL + parameter I'm using to test is:

https://script.google.com/a/macros/--DOMAIN--/s/--SCRIPTID--/exec?story=3

Can anyone give me some ideas on why it's not working?

回答1:

TypeError: Cannot read property "parameter" from undefined. (line 2, file "Code", project "singleStory")

This tells you that the object you expect to contain the named property "parameter" is undefined.

Looking at your code (e.parameter.story), that's referring to the event parameter e. For those unfamiliar with this, when it's invoked in a deployed Web App, the specially-named doGet() function receives an event parameter, which is named e in this example.)

Why is e undefined here?

One reason that you might see this is if you're running the function from the debugger, not testing it as a web app. That's not your case, Kevin, since you are entering a URL into the browser to try to launch the web app.

The problem turns out to be in the Templated HTML. The very first statement in your HTML is:

<? var data = doGet(); ?>

This causes trouble as soon as we attempt to .evaluate() the template, as it re-invokes the doGet() function, this time without any event object. And it's that time around that spits out the error message.

You likely meant to do this, instead, to get the data from your spreadsheet:

<? var data = getData(); ?>

With that change in place, you now receive the event parameter e (which you always did...) and the code carries on. Until the next bug:

ReferenceError: "i" is not defined. (line 3, file "Code")

Now things get tricky, because the error is being reported against this statement in Code.gs:

return HtmlService
    .createTemplateFromFile('Index')
    .evaluate()
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);

But wait! Wasn't i just defined in line 2? Yes, it was... However this error is about evaluate() trying to fill out the template, and your code doesn't yet set i for that. You'll need to break up this statement to first get the template, then set parameters for it, and finally evaluate it. Like this:

function doGet(e) {
  var i = e.parameter.story;

  // First, get the template
  var template = HtmlService.createTemplateFromFile('Index');

  // Second, set template parameters
  template.i = i;

  // Finally, evaluate() the template
  return template.evaluate()
                 .setSandboxMode(HtmlService.SandboxMode.IFRAME);

}  // <-- You had this on the other side of 'getData()'

That should get you rolling. You've got other errors:

  • The blocking of your functions is wrong, you want getData() at global scope, not within doGet().
  • You'll probably have to debug your template, follow the guidance in Debugging templates.
  • Templated code is enclosed <? thusly ?>, not <?= like this ?>.