Home > Blockchain >  Google Apps Script close HTML window without button, on demand
Google Apps Script close HTML window without button, on demand

Time:07-19

for some time I've been struggling how to properly run and close "Loader 360". First I will write some basic informations

My assumptions

  • I would like to have only 1 HTML file with loader
  • I would like to use it in different functions

How I see it should work

  1. Rune some function
  2. Run Loader
  3. Send information to close loader

How I handle with this problem at this moment (I hate this solution but at this moment I don't know how to manage it in different way)

I have 3 different functions (code below)

  1. Open Loader
  2. Close Loader
  3. Open loader with automatic close window when function stops.

I have 3 different HTML files (for the same Loader)

  1. Run Loader
  2. To close Loader
  3. Loader is closed automatically when the function stops.

So now when I run function and I would like to have a loader when this function is  runned I do something like this:

runLoader();
someFunction();
closeLoader();

but as you can see this solution is not so pretty because I have 2x HTML files for exactly the same thing. For one function I have separate 3rd HTML with an extra script which closes a window when the function stops, and I can't imagine making the same for eg20 different functions.

Do you have any suggestions on how to handle this problem ?

enter image description here

Function to start loader

function runLoader() {
  var htmlOutput = HtmlService
    .createHtmlOutputFromFile('Loader360')
    .setWidth(215)
    .setHeight(200);
  SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Loading...');
      }

Function to close loader

function closeLoader() {
  var htmlOutput = HtmlService
    .createHtmlOutputFromFile('CloseLoader360')
    .setWidth(215)
    .setHeight(200);
  SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Loading...');
}

HTML - Open Loader 360

<!DOCTYPE html>
<html>
    <head>
  <meta name="viewport">
  <style>
    .loader {
      border: 16px solid #f3f3f3;
      border-radius: 50%;
      border-top: 16px solid #3498db;
      width: 120px;
      height: 120px;
      -webkit-animation: spin 2s linear infinite;
      /* Safari */
      animation: spin 1s linear infinite;
      margin-left: auto;
      margin-right: auto;
    }
        /* Safari */
    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }
          100% {
        -webkit-transform: rotate(360deg);
      }
    }
        @keyframes spin {
      0% {
        transform: rotate(0deg);
      }
          100% {
        transform: rotate(360deg);
      }
    }
  </style>
</head>
    <body>
      <div ></div>
  <script>
          </script>
</body>
    </html>

HTML - Close Loader 360

<!DOCTYPE html>
<html>
    <head>
  <meta name="viewport">
  <style>
    .loader {
      border: 16px solid #f3f3f3;
      border-radius: 50%;
      border-top: 16px solid #3498db;
      width: 120px;
      height: 120px;
      -webkit-animation: spin 2s linear infinite;
      /* Safari */
      animation: spin 1s linear infinite;
      margin-left: auto;
      margin-right: auto;
    }
        /* Safari */
    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }
          100% {
        -webkit-transform: rotate(360deg);
      }
    }
        @keyframes spin {
      0% {
        transform: rotate(0deg);
      }
          100% {
        transform: rotate(360deg);
      }
    }
  </style>
</head>
    <body>
      <div ></div>
  <script>
         setTimeout(function(){ google.script.host.close(); },0.1)
          </script>
</body>
    </html>

code in HTML used to run one function

<script>
              google.script.run
                .withSuccessHandler(google.script.host.close)
                .applayBomTemplateToAllRows();
                </script>

Example

function onEdit(e) {

  //Get Sheet Basic ifnormation
  let activeSheet = activeSpreadsheet.getActiveSheet();
  let activeSheetName = activeSheet.getName();

  // Get sheet information
  let rowNumberWithModification = SpreadsheetApp.getActiveRange().getRow();
  let columnNumberWithModification = preadsheetApp.getActiveRange().getColumn();

  if ((rowNumberWithModification === 1) && (columnNumberWithModification === 1)) {
    runLoader(); //Here I would like to run a loader because I know that next function will take some time and I would like to inform user that something is calculating in background
    setDescription(); //function set for example red color of the font 
    closeLoader();
  }
  else {
    runLoader();
    usePainter(); //Painter will set a correct shape of the, let say 10rows
    closeLoader();
  }
}

CodePudding user response:

Might I suggest a modified procedure. I don't know where runLoader() is executed but that is really all you need. Then there is only 1 HTML. When the page loads it runs the spinner and google.script.run to run someFunction(). When someFunction completes it runs the callback function in the client and closes the spinner.

I have edited my answer to address the question about using loader with different functions.

I use templated HTML to pass a variable option to the HTML Template to tell it which option has been selected. That option is then passed back to the client to tell it which function to run.

So in answer to the question, no additional HTML files are necessary.

I tested the method of calling variable functions proposed by TheMaster and it works. I've edited my answer to include it as it shows a more elegant way of doing it.

It took me a little while to wrap my head around it but then I realized

google.script.run().someFunction() is equivalent to google.script.run()["someFunction"]()

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      .... put all your style stuff here
    </style>
  </head>
  <body>
    <div ></div>
    <script>
      let option = <?= option ?>;  // <- this line was added
      google.script.run.withSuccessHandler(
        function() {
          google.script.run.close();
        }
      )[option]();  // <- add option added here
    </script>
  </body>
</html>

Code.gs

function onEdit(e) {

  // your code here

  if ((rowNumberWithModification === 1) && (columnNumberWithModification === 1)) {
    runLoader("setDescription");
  }
  else {
    runLoader("usePainter");
  }
}

function runLoader(option) {
  var htmlOutput = HtmlService
    .createTemplateFromFile('Loader360')
    .setWidth(215)
    .setHeight(200);
  htmlOutput.option = option;
  SpreadsheetApp.getUi().showModalDialog(htmlOutput.evaluate(), 'Loading...');
}

function setDescription() {
  // do something
}

function usePainter() {
  // do something else
}

Reference

  • Related