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
- Rune some function
- Run Loader
- 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)
- Open Loader
- Close Loader
- Open loader with automatic close window when function stops.
I have 3 different HTML files (for the same Loader)
- Run Loader
- To close Loader
- 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 ?
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