0

I have a Google Apps Script called from Google Sheets. The .GS file calls the .HTML form. I am trying to test that a forLoop and a async function can run one after the other. I had a previous question but it was marked as a dupe to this even though that question does not solve my issue nor address the real problem and is really just referring to links that also do not answer the question.

my gs file calls the function as it should. The form show us as it should but it does not print out the alert.

Is there any way to do this?

If not, how do we have a Google Apps Script in Google Sheets that can run a function and show a progress meter of said function via a JavaScript library like fluid-meter.js (fiddle here) The tutorial for fluid-meter.js is here

Plus it does work, just only after everything else is run; I want it to run async with another function.

function callForm()
{
    //Call the HTML file and set the width and height
    //var html = HtmlService.createHtmlOutputFromFile("tracker_form")
    var html = HtmlService.createHtmlOutputFromFile("test_async")
        .setWidth(450)
        .setHeight(300);

    //Display the dialog
    var dialog = SpreadsheetApp.getUi().showModalDialog(html, "Select the relevant draft");
}
<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://fonts.googleapis.com/css?family=Oxygen|Raleway&display=swap" rel="stylesheet">
    <base target="_top">
        
   
   <!--<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">-->
   <link rel="stylesheet" href="https://drive.google.com/uc?export=view&id=1iKnmVGSAh70SSwzLERkTdcYT85cpJeWH">
   
      
   <!-- <script src="https://code.jquery.com/jquery-1.12.4.js"></script> -->
   <script src="https://drive.google.com/uc?export=view&id=1iFtElfW5_mtWZpEDHdoE9zPYRaMmGO1y"></script>
  </head>
  <body>
  
  <br>
  <h3>This is the body</h3>
  
    
  </body>
  
  <script>
  
  async function calc2(i, j) {
    return i + j;
}

async function useForLoop() {
    let total = 0;
    for (let i = 0; i <= 10000; i++) {
        for (let j = i; j > 0; j--) {
            total += await calc2(i, j);
        }
    }
    
    alert("total is:  "+total); 
    return total;
}
  
  
  
  
  </script>
  
  
  
</html>
ASheppardWork
  • 95
  • 1
  • 2
  • 12
  • Can I ask you about your question? About `I am trying to test that a forLoop and a async function can run one after the other.`, can I ask you about the sample output you expect? And, about `If not,,,`, how should we do this? – Tanaike Nov 05 '20 at 03:20
  • believe it or not I got the stupid thing to work. I had to make some updates. Will update the question. – ASheppardWork Nov 05 '20 at 03:28
  • Thank you for replying. I understood about it. I would like to wait for the update. – Tanaike Nov 05 '20 at 03:30

1 Answers1

0

Believe it or not I got this to work, finally.... Here is my working code.

The output in the console is like this-

calc2 is: 106
total is: 509535
calc2 is: 105
total is: 509640
calc2 is: 104
total is: 509744
...

In the .gs file:

    function callForm()
    {
        //Call the HTML file and set the width and height
        //var html = HtmlService.createHtmlOutputFromFile("tracker_form")
        var html = HtmlService.createHtmlOutputFromFile("test_async")
            .setWidth(450)
            .setHeight(300);

        //Display the dialog
        var dialog = SpreadsheetApp.getUi().showModalDialog(html, "Select the relevant draft");
    }
    <!DOCTYPE html>
    <html>
        <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link href="https://fonts.googleapis.com/css?family=Oxygen|Raleway&display=swap" rel="stylesheet">
        <base target="_top">
            
       
       <!--<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">-->
       <link rel="stylesheet" href="https://drive.google.com/uc?export=view&id=1iKnmVGSAh70SSwzLERkTdcYT85cpJeWH">
       
          
       <!-- <script src="https://code.jquery.com/jquery-1.12.4.js"></script> -->
       <script src="https://drive.google.com/uc?export=view&id=1iFtElfW5_mtWZpEDHdoE9zPYRaMmGO1y"></script>
      </head>
      <body >
      
      <br>
      <h3 >This is the body</h3>
      
       <button type="button" onclick="printRestults();">test</button>
       
        
      </body>
      
      <script>
      var returntotal
      
      async function calc2(i, j) {
        var x = i + j;
        
        console.log("calc2 is:  "+x);
      
        return i + j;
    }

    async function useForLoop() {
        let total = 0;
        for (let i = 0; i <= 100; i++) {
            for (let j = i; j > 0; j--) {
                total += await calc2(i, j);
                console.log("total is:  "+total);
            }
        }
        
        
        
        returntotal = total;
    }

    function printRestults(){

    useForLoop();


    console.log("returntotal is:  "+returntotal);

    }
      
      
      
      
      </script>
      
      
      
    </html>

UPDATE: This answer only works with functions that are not nested. In this manner I cannot use it for my original project. which is below---

gs. file--

function showDraftResults(passingbackinfo){
  

 passingbackinfo = passingbackinfo.replace(/\\/g, "");
  
 passingbackinfo = passingbackinfo.replace(/"/g, '\''); 
  
 passingbackinfo = passingbackinfo.replace(/''/g, '\'');  
 
 passingbackinfo = passingbackinfo.replace(/'/g, "");  

  
 var mydraftId=''; 
 var mysendEmail='';
 var mysendname='';
 var myreplytoemail='';
  
  
 passingbackinfo = passingbackinfo.split(';');
  
  for(var a in passingbackinfo ) {
  
     
     mydraftId = passingbackinfo[a-3];
     mysendEmail = passingbackinfo[a-2];
     mysendname = passingbackinfo[a-1];
     myreplytoemail = passingbackinfo[a]
    
  
  };
  
  
  sendMail(mydraftId,mysendEmail,mysendname,myreplytoemail,'UA-123456789-1');
      
}  


function sendMail(draftId,sendEmail,sendName,replyTo,analyticsID) {

  var sendName = sendName;
  
  var replyTo = replyTo;
  
  var analyticsID = analyticsID;
    
  var draft = GmailApp.getMessageById(draftId);
  
  var draftCC = draft.getCc();
  
  var draftBCC = draft.getBcc()
      
  var subject = draft.getSubject();

  var body = draft.getBody();
  
  var email_to_send = sendEmail;

      
formattedEmails (email_to_send,subject,body,analyticsID,sendName,replyTo,draftCC,draftBCC);

  
}



  

function formattedEmails (email_to_send,subject,body,analyticsID,sendName,replyTo,draftCC,draftBCC){

    
    var newbody = '';
   
  
    var imgURL = "https://ssl.google-analytics.com/collect?"
    + "v=1&t=event"
    + "&tid=" + analyticsID
    + "&z="   + Math.round((new Date()).getTime()/1000).toString()
    + "&cid=" + Utilities.getUuid()
    + "&ec=" + encodeURIComponent("Email Open")
    + "&ea=" + encodeURIComponent(subject.replace(/'/g, ""))
    + "&el=" + encodeURIComponent(email_to_send);
  
  var imgLink = "<img src='" + imgURL + "' width='1' height='1'/>";
  
  newbody = body;  
  
  newbody += imgLink
  
    
    GmailApp.sendEmail(
     email_to_send,
     subject,
     newbody, 
      {htmlBody: newbody, cc: draftCC, bcc: draftBCC, name: sendName, replyTo: replyTo}
     
   );
    

    newbody = '';
    




//console. clear();
}

html file--


    <!DOCTYPE html>
    <html>
    
        <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link href="https://fonts.googleapis.com/css?family=Oxygen|Raleway&display=swap" rel="stylesheet">
        <base target="_top">
            
       
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
      
          
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
     
       
    
      
      <style>
        fieldset {
          border: 0;
        }
        label {
          display: block;
          margin: 30px 0 0 0;
        }
        .overflow {
          height: 200px;
        }
      </style>
     <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    
      
        <script>
      $( function() {
        $( "#List" ).selectmenu();
        $( "#groupList").selectmenu();
        $( "#sendname").autocomplete();
        $( "#replyto").autocomplete();
        $( "#fluid-meter-3" ).text;
     
     
    
      } );
      </script>
      
      
      
      
      
        </head>
    
        <body onload="addList();addGroupList();">
        <div>
            <form id="Form" action="#" >
                <fieldset>
                
                <div class="masterForm">
                    <select id="List" name="draftList">
                        <option>...</option>
                    </select>
                    <h3 id="result">Choose a Draft</h3>
                
                <br/>
                <br/>
                
                    <select id="groupList" name="groupdraftList">
                        <option>...</option>
                    </select>
                   <h3 id="groupresult">Choose a Group</h3>
                
                <br/>
                <br/>
                
                <input type="text" id="sendname" name="sendname" title="type &quot;a&quot;" class="ui-autocomplete-input" autocomplete="off" value="Team">
                   <h3 style="height:10px;">Enter Send As Name</h3>
                   <hr style="height:10px; visibility:hidden;" />
           
               <br/>
               <br/>
                
               <input type="text" id="replyto" name="replyto" title="type &quot;a&quot;" class="ui-autocomplete-input" autocomplete="off" value="team@team.com">
                   <h3 style="height:10px;">Enter Reply To EMail</h3>
                   <hr style="height:10px; visibility:hidden;" />
                            
               <br/>
               <br/>
               <button class="ui-button ui-corner-all ui-widget" type="button" onclick="updateAndSend();">Send Email to Selected Group</button>
               </div>
               
               <br/>
               <br/>
               <div class="container" >
               <div class="row">
               <div class="col text-center">
               
               <div class="col  text-center">
               <div id="fluid-meter-3"></div>
               
               </div>
               
               </div>
               
               
               </div>
               </div>
              
               
              </fieldset> 
            </form>
          </div>
        </body>
    
    
    
    
    
    
        
    <script src="https://bootstrap-4-1-1.min.css"></script>
       
    <script src="js/js-fluid-meter.js"></script>
    
    
        <script>
        
        
        
        var returnsendasname;
        
        var returnreplyto;
        
        var returndraftid;
        
        var returngroupid;
        
        var returnemails_split = [];
        
        var returncountemails;
        
        var fluidpercent = 0;
        
        function GetSelectedDraft(){
        var e = document.getElementById("List");
        var selectedOption = e.options[e.selectedIndex];
        
        document.getElementById("result").innerHTML = selectedOption.text;
        
        returndraftid = selectedOption.value;
        
       
        }
        
        
        function GetSelectedGroup(){
        var e = document.getElementById("groupList");
        var selectedOption = e.options[e.selectedIndex];
        
        document.getElementById("groupresult").innerHTML = selectedOption.text;
        
        returngroupid = selectedOption.value;
        
        
        }
        
        
        function GetSendAsName(){
        
        var name = document.getElementById("sendname");
        
        returnsendasname = name.value;
        
        
        }   
        
        function GetReplyToEmail(){
        
        var emailname = document.getElementById("replyto");
        
        returnreplyto = emailname.value;
        
        
        } 
        
        
        function addList()
        {
        google.script.run.withSuccessHandler(writeList).withFailureHandler(onFailure).getDraftId();
        }
        
        
        function addGroupList()
        {
        google.script.run.withSuccessHandler(writeGroupList).withFailureHandler(onFailure).getGroups();
        }
    
    
        function writeList(options)
        {
          options = options.sort(function(a, b){
            if(a.subject < b.subject) return -1;
            if(a.subject == b.subject) return 0;
            return 1;
            });
    
          var dropdown = $("#List");
          dropdown.empty();
    
          for(var i = 0, numOptions = options.length; i < numOptions; ++i)
           {
             dropdown.append('<option value="' + options[i].id + '">' + options[i].subject + '</option>');
           }
    
    
        }
            
            
         function writeGroupList(options)
         {
           options = options.sort(function(a, b){
             if(a.group < b.group) return -1;
             if(a.group == b.group) return 0;
             return 1;
           });
              
           var groupdropdown = $("#groupList");
           groupdropdown.empty();
              
           for(var i = 0, numOptions = options.length; i < numOptions; ++i)
            {
              groupdropdown.append('<option value="' + options[i].emails + '">' + options[i].group + '</option>');
            }
              
    
          }
            
    
    
    
    
     
        
        
       
        var fm3 = new FluidMeter();
        fm3.init({
        targetContainer: document.getElementById("fluid-meter-3"),
        fillPercentage: fluidpercent,
        options: {
        fontSize: "30px",
        drawPercentageSign: false,
        drawBubbles: false,
        size: 300,
        borderWidth: 19,
        backgroundColor: "#0C0C0C",
        foregroundColor: "#EBEBEB",
        foregroundFluidLayer: {
        fillStyle: "#0F98DC",
        angularSpeed: 30,
        maxAmplitude: 8,
        frequency: 30,
        horizontalSpeed: -20
        },
        backgroundFluidLayer: {
        fillStyle: "#0061AC",
        angularSpeed: 100,
        maxAmplitude: 7,
        frequency: 22,
        horizontalSpeed: 20
        }
        }
        });
        
    
        
        
    
        
        function sleep(milliseconds) {
        const date = Date.now();
        let currentDate = null;
        do {
        currentDate = Date.now();
        } while (currentDate - date < milliseconds);
        }
        
        function GetEmailCount(){
        
         var emails_to_send = returngroupid;
         var emails_split = emails_to_send.split(','); 
           
            let count_Emails = 0;
      
            for (let j = 0; j < emails_split.length; j++) {
           
           count_Emails++;
           
           }
        
           returncountemails = count_Emails;    
        }
        
       function GetEmailsToSend(){
        
         var emails_to_send = returngroupid;
         var emails_split = emails_to_send.split(','); 
           
     
           returnemails_split = emails_split;
           
            //alert('Getting Emails to Send:  '+returnemails_split); 
           
           
        }
        
        
       function updateAndSend(){
       
        // sets the returngroupid
        GetSelectedGroup();
           
        // sets the returnemails_split
        GetEmailsToSend();
       
        //alert('returnemails_split:  '+returnemails_split[0]); 
        
        
        returnemails_split.forEach(myFunction);
        
        
        function myFunction(item, index, arr){
        
            packageupresults(item);
            
            alert('SetPercentage Index: '+index);
            
            fm3.setPercentage(Math.floor((index/returnemails_split.length) * 100));
            
            
        
        
        }
        
        
           
       
       alert('Emails Sent, you can close the app');  
       
       
       }
        
    
        
        
        
        
        function packageupresults(details)
          {
          
           
    
           // sets the returnsendasname
           GetSendAsName();
           // sets the returnreplyto
           GetReplyToEmail();
           // sets the returndraftid
           GetSelectedDraft();
    
           // sets the returncountemails
           GetEmailCount();
    
           
           
           var emails_split = details;
                         
                         emails_split = emails_split.replace(/^\s*/, "").replace(/\s*$/, "");
                         var mysendname = JSON.stringify(returnsendasname);
                         var myreplytoemail= JSON.stringify(returnreplyto);
                         var mydraftid = JSON.stringify(returndraftid);
                         var mysendemail = JSON.stringify(emails_split)
                         var passingbackinfo = mydraftid+';'+mysendemail+';'+mysendname+';'+myreplytoemail
                         passingbackinfo = JSON.stringify(passingbackinfo)
                         google.script.run.showDraftResults(passingbackinfo)
    
                       
            
              return true;
            }
            
          function onFailure(err)
            {
              alert('There was an error!' + err.message);
            }
    
     
    
      addList();
      
      
      
    
     
      </script>
    
        
        
    <html>

ASheppardWork
  • 95
  • 1
  • 2
  • 12
  • There is 1 very large caveat to all this. It won't work with nested functions. My original app that I was trying to merge this with requires nested functions. In this case the async does NOT work and the functions run in the order they are called. Truly Disappointed. – ASheppardWork Nov 05 '20 at 20:55