HtmlService not working from doPost() - scriptable

2019-06-11 00:48发布

问题:

I'd like to use doPost() with HtmlService as an async dispatcher to call other functions with. The async capability is important for performance - not having to wait synchronously for a spreadsheet operation to complete, so that is what the HtmlService is for. Here is what I have code-wise:

 function doGet(e) {
      var app = UiApp.createApplication();
  var button = app.createButton('Click Me');
  app.add(button);
  var handler = app.createServerHandler('myClickHandler');
  button.addClickHandler(handler);
  return app;
}

function myClickHandler(){
  sendHttpPostSelf();
}
function doSomething() {
  Logger.log('I was called Now!');
  return;
}
function sendHttpPostSelf() {
  var payload = {
      "name" : "name",
      "comment" : "comment",
      "screenshot" : "screenshot"
  };
  var options = {
      "method" : "post",
      "payload" : payload
    };
var url="https://script.google.com/macros/s/AKfycbzlVoiDQMbLe4yliErDoNub6A0m3tijSfPAUMEBENgIikQnLQ_H/exec";
var resp=UrlFetchApp.fetch(url,options);
Logger.log(resp.getContentText());//.getContent());
} 
function doPost(e){
  var dbg;
  var dbg=true;
  if (dbg==true)for (var i in e.parameter)Logger.log("FormSubmit:doPost "+ i + ": " + e.parameter[i]);
  return HtmlService.createHtmlOutputFromFile("myFile.html");
}

//ANd HERE IS myFile.html
<script>
 function onFailure(error) {
   //alert('Error will Robinson!: '+error.message);
     Logger.log('Error will Robinson!: '+error.message);
  }
  function onSuccess(error) {
    //alert('Gotter Done');
    Logger.log("FormSubmit:doPost",'Gotter Done');
  }
  google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).doSomething();
</script>

The httpPostSelf() works okay and doPost() receives the parms fine but my problem is that HtmlService.createHtmlOutputFromFile("myFile.html") does not call doSomething() properly? I only see a lot of cryptic caja parsing in Logger.log
--END OF ORIGINAL QUESTION--

Question Addition
Dear Corey:

Appreciate your feedback on doPost() not handling HtmlService and your proposed async examples. You are correct, button-click events are async..but my question is still unanswered. To clarify, allow me to please elaborate further on my question. What I need to work is an async script call to a web app(sounds like AJAX I guess). All works in my sample script except for the async. An alternative URL is used then in my previous example to call a separate web app instead of a self-post:

var url="https://script.google.com/a/macros/commet.com/s/AKfycbwJ4WM3U5POEWF9XqFzjaV_9TiNLspKb7kePAih59vsWllA0og/exec";

The async is critical to performance because I have 2000 plus lines of spreadsheet code to conduct basic sheets operations: inserts, deletes, updates, moves, sorts..I have the script nicely packaged into objects with methods. The sheet ops script is currently packaged with the UiApp script in Sites and callable synchronously. After many painful rewrites, some of the more complex ops(sorts and moves) are still taking up to 7 seconds to complete.

I want to migrate the sheet op script to spreadsheet Web Apps. The sheet op/Web App should be callable async from my Site UiApp. For example, when my Site calls for a sort it will simply unleash a sendHttpPost with parms to the Web App and then the the Site will carry on about completing its GUI business(doing the sort client-side) without waiting 7 seconds for the spreadsheet to complete its sort. WaLaa!

The web app with parms passing correctly work in my sample script but the UrlFetchApp.fetch unfortunately(for me) is synchronous. THAT is why I attempted the async HtmlService-google.script.run. I tried calling doGet() with HtmlService as a web app and that does not work either using UrlFetchApp.fetch. The only way HtmlService works as a Web App is when called from a push-button with a form submit...I need a scriptable interface.

Any scriptable alternatives to UrlFetchApp.fetch - HtmlService?

Comment HtmlService Web App Access
Here are my test results for when HtmlService works from a Webapp:
doPost()
- works when submitted with Submit button in FormPanel
- does not work when submitted with UrlFetchApp.fetch(needed for script access)
Comment: Any way to get doPost() to work with UrlFetchApp.fetch would be great to know for programming forms!

doGet()
- works from a browser-url
- does not work when submitted with UrlFetchApp.fetch(needed for script access)
If any is inaccurate please reply with script examples. What I need is UrlFetchApp.fetch script access.

回答1:

You are trying to contact HtmlService from UiApp via doPost, which will not work. UiApp's doPost can only accept UiApp responses, and HtmlService doesn't even use doPost - it uses the google.script.run syntax exclusively. What you are seeing is the UiApp code on the client being completely confused by the HtmlService-type response.

But I think you are perhaps confused about how both of these services work, as both UiApp ServerHandler callbacks and HtmlService google.script.run call server scripts asynchronously without any need for you to do something custom or tricky. There is no need to mix and match the two, and no need to involve doPost at all - that is exclusively intended for uploading files via UiApp (which is why HtmlService doesn't support it, since it has a simpler syntax for uploading files).

This is an async dispatcher in UiApp:

function doGet() {
  var app = UiApp.createApplication();
  app.add(app.createButton("run foo", app.createServerHandler("foo")));
  app.add(app.createButton("run bar", app.createServerHandler("bar")));
  return app;
}
function foo() { Logger.log("ran foo!");  }
function bar() { Logger.log("ran bar!");  }

And here is the same in HtmlService:

function doGet() {
  return HtmlService.createHtmlOutput(
      "<button onclick='google.script.run.foo()'>run foo</button>" +
      "<button onclick='google.script.run.bar()'>run bar</button>"); 
}
function foo() { Logger.log("ran foo!");  }
function bar() { Logger.log("ran bar!");  }

To answer a comment below, in UiApp you send values from the client to the server via addCallbackElement. In HtmlService, you just add parameters to your server function:

function doGet() {
  return HtmlService.createHtmlOutput(
      "<button onclick='var foo = document.getElementById(\'myTextBox\').value; google.script.run.foo(123, foo)'>run foo</button>"
}
function foo(x, y) { Logger.log("ran foo with params " + x + " and + "y");  }

That should log "ran foo with params 123 and contents of myTextBox". You should be able to generalize from there (and I'd suggest reading the user guide as well.)



回答2:

When you run scripts inside HtmlTemplates that you make, they do not have access to the Apps Script libraries (but you can call your Apps Script functions). For example, you can't call Logger.log() from your Html page. You should use console.log(). That will log to your web console. (Ctrl+Shift+J in Chrome).