0

I have lost an entire day fighting this and none of the search results I am finding are helping me.

I am writing script in Google Sheets and using Chrome browser on Windows 10 OS. I need this to run in Chrome at minimum because most of my company uses Chrome.

When my code is in full force, everything works fine but the onsubmit action in my html form calls the function in my gs TWICE and I can't figure out why.

What I am seeing is; regardless of content in my html file or gs function, if my function takes ten seconds or longer to execute then it is called a second time. How could this be? What am I doing wrong?

Step by step, here is what I am doing and what happens.

First, via add-on menu, I call the initial function that spawns the HTML model window containing the form.

function importPool() {
var ui = SpreadsheetApp.getUi();
var html = HtmlService.createHtmlOutputFromFile("importPool")
.setWidth(750)
.setHeight(300);
var dialog = ui.showModalDialog(html, "Import pool");
}

This launches "importPool.html"

<!DOCTYPE html>
<html>
<head>
<base target="_top">

</head><body>
<form id="myForm" onsubmit="processForm(myForm);">
    <div style=" text-align: left; text-indent: 0px; padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px;">
        <table width="100%" border="1" cellpadding="2" cellspacing="2" style="background-color: #c0c0c0;">
    
            
            <tr valign="top">
                <td style="border-width : 0px;text-align: left"></td>
                <td style="border-width : 0px;text-align: right">
                    <input type="button" value="Cancel" onclick="google.script.host.close()"><input type="submit" value="Import">
      </td>
            </tr>
    
        </table>
    </div>
</form>
<script>
function processForm(formdata){
  google.script.run.processImport(formdata);
  google.script.host.close();
}
</script>
</body>

</html>

I click my "Submit" button and that calls my processImport function within my gs. For testing purposes this function only contains

function processImport(form) {
Logger.log("I am running!");
Utilities.sleep(12000); 
}

As I mentioned, if I reduce the timer so the function takes less than ten seconds to execute, the function is only run once for every click of the Submit button. However if the function takes longer than ten seconds to execute it is run twice when I click Submit. It runs the first time as normal, then almost exactly ten seconds into the run time it executes the function again, top-to-bottom.

What could be causing this? I am convinced I am doing something stupid but I can't find it. Please help!

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Dave
  • 87
  • 1
  • 11

1 Answers1

1

Improvement suggestions

  1. Replace inline event handlers (onsubmit= and onclick= attributes) by event listeners
  2. Use withSuccessHandler and withFailureHandler when using google.script.run
  3. Add google.script.host.close() inside the callback of witchSuccessHandler
  4. Add the following at the beginning of your <script></script>
// Prevent forms from submitting.

  function preventFormSubmit() {
    var forms = document.querySelectorAll('form');
    for (var i = 0; i < forms.length; i++) {
      forms[i].addEventListener('submit', function(event) {
        event.preventDefault();
      });
    }
  }
  window.addEventListener('load', preventFormSubmit);

From https://developers.google.com/apps-script/guides/html/communication#forms

Note that upon loading all forms in the page have the default submit action disabled by preventFormSubmit. This prevents the page from redirecting to an inaccurate URL in the event of an exception.


From Introduction to events

You can find HTML attribute equivalents for many of the event handler properties; however, you shouldn't use these — they are considered bad practice. It might seem easy to use an event handler attribute if you are just doing something really quick, but they very quickly become unmanageable and inefficient.

Please bear in mind that google.script.run calls are asynchronous (the code after them will be executed before the server side function ends)

Related

Rubén
  • 34,714
  • 9
  • 70
  • 166
  • Followed all of your suggestions and it works now! Only runs once, and no more background HTML errors either. BUT, one more question...in all of this where should the "google.script.host.close();" command live? If I place it directly after my run command the window closes before the function is triggered. I feel like I could add a timer delay but that feels clunky. – Dave Aug 12 '20 at 16:22
  • 1
    @Dave put it inside callback function of `withSuccessHandler` – Rubén Aug 12 '20 at 16:25
  • That was it! Thank you! – Dave Aug 12 '20 at 17:20