Search code examples
htmljqueryvalidationgoogle-apps-scriptjquery-ui-dialog

HTML form validation with Google Apps Script's HTML Service


I'm trying to use HTML form validation when using Google Apps Script's HTML Service. As another user asked, according to the documentation example, you must use a button input instead of a submit input. Using a submit button seems to do the validation, but the server function is called anyway. The answer given to that user didn't work for me. Also, I want to call two functions when submitting the form and this can make it more complex.

This is what I'm trying to do: The user fills a form and I generate a Google Doc and give him the URL. When he clicks the submit button, I show him a jQuery UI dialog saying "Your document is being created" with a nice spinner. Then, when the document is generated, I give him the link. I use the success handler to show the result when the Google Doc stuff is finished, but meanwhile I need a function to show the spinner. I don't know if there is a better way to do that than adding another function to the onclick event and maybe it can be damaging the process in some way. Is there a way not to call any of these functions if the form is not valid (using HTML validation)?

This is a simplified version of my code:

Code.gs

function generateDocument(formObject) {
  var doc = DocumentApp.create("Document name");
  ...
  return doc.getUrl();
}

Page.html

<main>
  <form id="myForm">
    ...
    <input type="button" value="Generate document" 
        onclick="showProgress();
            google.script.run
            .withSuccessHandler(openDocument)
            .generateDocument(this.parentNode);"/>
  </form>
  <div id="dialog-confirm" title="Your document">
    <div id="dialog-confirm-text"></div>
  </div>

Javascript.html

$( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, modal: true });

function showProgress() {
  $( "#dialog-confirm" ).dialog({ buttons: [ { text: "Cancel", click: function() { $( this ).dialog( "close" ); } } ] });
  $( "#dialog-confirm" ).dialog( "open" );
  $( "#dialog-confirm-text" ).html( "<br />Wait a second, your document is being generated...<br /><br /><img src='https://i.sstatic.net/FhHRx.gif' alt='Spinner'></img>" );
  return false;
}

function openDocument(url) {
  $( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, width: 400, buttons: [ { text: "Ok", click: function() { $( this ).dialog( "close" ); } } ] });
  $( "#dialog-confirm-text" ).html( '<br /><a href="' + url + '" target="_blank">Click here to open and print your document!</a>' );
  return false;
}

All three HTML docs are joined together (and working with its respective tags) with the include function as recommended in the documentation.

The Cancel button in the dialog will close it but won't stop the doc being created. Is it possible to stop this process?


Solution

  • Move the function call to the <form> element; remove any function call from the submit input element; and put intermediary JavaScript code into a <script> tag:

    <input tabindex="9" type="submit" value="Save Input" id='idInputBtn'>
    
    
    <form id="myInputForm" name="input" onsubmit="fncWriteInput(this)">
    
    <script>
      window.fncWriteInput= function(argTheInfo) {
      // Do additional checks here if you want
      var everythingIsOk = . . . . . . . ;
    
      if (everythingIsOk) {
        google.script.run
          .withSuccessHandler(openDocument)
          .generateDocument(argTheInfo);
        };
      };
    

    Notice that this.parentNode gets removed to the arg of the function call, and just use this in the function argument because the function is getting called from the <form> element, which is the parent.

    If there are any errors, the form will not be submitted, and the user will get a msg that something was wrong. No code will run.

    This is pseudo code, but I do use a set up like this in my application. But use developer tools and you can put a break point right in your browser and step through every line to test it without needing to put in console.log statements.