Re: How to show loading indicator in addon sidebar while Google Picker is open?

731 views
Skip to first unread message
Message has been deleted

Alex

unread,
Sep 30, 2019, 7:18:40 AM9/30/19
to Google Apps Script Community
Hi

You can init an infinity loader (gif is fine) after click open the file dialog and hide it after the picker is resolved. 

On Monday, September 30, 2019 at 1:02:54 PM UTC+3, Luke Collins wrote:

Good morning guys,

I followed this tutorial: https://developers.google.com/apps-script/guides/dialogs#file-open_dialogs and I can open a Google Picker after clicking a button inside my addon sidebar.

I want to do 2 things for better UX for my users:

- The first thing is when the Google Picker is open, I want to show a loading indicator inside my addon sidebar (to prevent users from interacting with the sidebar), so that users can only interact with the Google Picker until it's closed

- Immediately after users choose a document or directly close the Google Picker, the loading indicator in the addon sidebar will be disappeared, and users can interact with the addon sidebar normally

From the backend developers point of view, I think there must be some kinds of "socket" or "event" so that these 2 things can talk to each other.

But because the addon sidebar and the Google Picker dialog are 2 separated html files, I can't figure out how. So how can I do that?

Thanks.

Luke Collins

unread,
Sep 30, 2019, 8:01:20 AM9/30/19
to Google Apps Script Community
Thanks. But how to detect if the Google Picker is open or if it's resolved?

It can be detected inside the Google Picker dialog html, but how to detect it from the sidebar? They are 2 different html files.

Alan Wells

unread,
Sep 30, 2019, 10:13:23 AM9/30/19
to Google Apps Script Community
In the example that you referenced, there is a client side function:


   
function getOAuthToken() {
 
//Start spinner here

      google
.script.run.withSuccessHandler(createPicker)
         
.withFailureHandler(showError).getOAuthToken();
   
}



Notice that I added a comment for "//Start spinner here"
That's where you need to start the spinner indicating that the Google picker is in the process of opening.

There is also a success handler in that function named: createPicker

In the function named createPicker
you must stop the spinner.

function createPicker(token) {
try{
 
//Stop the spinner here

 
if (!token) {
 
throw new Error('No token for picker');
 
}

 
//Build the picker
}catch(e){
 
 myFuncForClientSideErrorHandling
(e);

}
}


There are probably many different systems for a spinner.  I have my own system, which has an empty DIV with a class name.  The code needs to find that DIV element, and change the class name, which causes the CSS to start an animation.

So there are multiple parts to the spinner system.

JavaScript - client side - Finds spinner HTML DIV element and adds or removes the class name
CSS - Multiple class names - one for animation to show the spinner
HTML - DIV for where the spinner will operate from

The CSS needs to center the spinner.

I don't know if you already have the CSS, JavaScript and HTML that you want for your spinner system.

In the code that builds the picker, you need to set a callback for the function that will run when the user clicks the button to select their picked choice.

    .setCallback(myFunkHereToRunWhenUserClicksSelectButton)


Once a file is selected from the Google picker, you could show the spinner again if you want.

Luke Collins

unread,
Sep 30, 2019, 11:07:36 AM9/30/19
to Google Apps Script Community
Thank you for your solution. But maybe my question is not clear.

What I want to achieve is: 
1. When the Google Picker is open, there is a loading indicator inside the addon sidebar (not inside the picker dialog)
2. When user closes the dialog or select a document (both make the dialog disappears), then the loading indicator inside the addon side is also disappeared. 

Because the function createPicker you said above is inside the html file of the picker dialog, so it can't control the sidebar html? Am I correct?

Alan Wells

unread,
Sep 30, 2019, 11:37:20 AM9/30/19
to Google Apps Script Community
The timing of my solution is different than what you want.  For what you want, you'd need to start the spinner spinning where I suggested that you stop it from spinning.  The HTML, CSS and JavaScript that controls the spinner would be separate from the picker code.  You need to make a function call to the spinner code from the picker code, but the picker code is separate.  And also, the HTML for the spinner is separate.  You can put the HTML for the spinner wherever you want it to be.  So, the spinner can be spinning in the sidebar, while a separate dialog for the Google picker is open.
Do you have something in mind for the spinner system?  I'm not sure what you are working with, or whether you're still looking for basic information.  I'm assuming that you don't have any code / CSS / html for the spinner?

On Monday, September 30, 2019 at 11:07:36 AM UTC-4, Luke Collins wrote:
Thank you for your solution. But maybe my question is not clear.

What I want to achieve is: 
1. When the Google Picker is open, there is a loading indicator inside the addon sidebar (not inside the picker dialog)
2. When user closes the dialog or select a document (both make the dialog disappears), then the loading indicator inside the addon side is also disappeared. 

Because the function createPicker you said above is inside the html file of the picker dialog, so it can't control the sidebar html? Am I correct?
There are probably many different systems for a spinner.  I have my own system, which has an empty DIV with a class name.  The code needs to find that DIV element, and change the class name, which causes the CSS to start an animation.

Luke Collins

unread,
Sep 30, 2019, 9:59:53 PM9/30/19
to google-apps-sc...@googlegroups.com
Thank you for your explanation,

About the spinner, I can use the code from here https://projects.lukehaas.me/css-loaders/, so I think the spinner code is not a problem for me.

What I still don't understand is: assume you have 3 html files:
1. sidebar.html
2. spinner.html
3. picker.html

All these html files contain html, css, js that you need to run each of them.

Inside the sidebar.html, when I need to open the Picker, I will call:

function openPicker() {
 
// Show spinner here
 
// For example, showSpinner()


  google
.script.run
   
.withSuccessHandler(function() { console.log('ok') })
   
.showPicker()
}

Above function will call this showPicker() function in Code.gs:

function showPicker() {
 
var html = HtmlService.createHtmlOutputFromFile('picker.html')
   
.setWidth(800)
   
.setHeight(600)
 
FormApp.getUi().showModalDialog(html, 'Select a file')
}

Inside the `picker.html`, I have a callback:

    function pickerCallback(data) {
       
var action = data[google.picker.Response.ACTION]
       
if (action === google.picker.Action.PICKED) {
           
var doc = data[google.picker.Response.DOCUMENTS][0]
           
var id = doc[google.picker.Document.ID]
           
var url = doc[google.picker.Document.URL]
           
var title = doc[google.picker.Document.NAME]
            document
.getElementById('result').innerHTML =
               
'<b>You chose:</b><br>Name: <a href="' + url + '">' + title + '</a><br>ID: ' + id
       
} else if (action === google.picker.Action.CANCEL) {
            google
.script.host.close()
       
}


       
// This is a good place to hide the spinner,
       
// but this is picker.html, so it can not control code in sidebar.html to hide the spinner
   
}


As you can see, the problem here is, the `sidebar.html` can only know when to show the spinner, not when to close it.

The logic to detect when we should close the spinner lies in the picker.html itself (only the picker knows when the user has selected a document or cancelled the picker). And I don't know how to pass that logic to the sidebar.html so that it can run
hideSpinner()

somewhere inside sidebar.html.

Luke Collins

unread,
Sep 30, 2019, 10:01:50 PM9/30/19
to Google Apps Script Community
Can you please give a code example to illustrate what you explained earlier. Maybe I didn't understand your solution

Luke Collins

unread,
Oct 1, 2019, 6:01:17 AM10/1/19
to Google Apps Script Community
I think I found the solution.

I can use the CacheService to store the data (if picker is open or not)

Then inside the sidebar.html, I can send request using setInterval to check if the picker is open or not

On Monday, September 30, 2019 at 10:37:20 PM UTC+7, aj.addons wrote:

Alan Wells

unread,
Oct 1, 2019, 8:53:01 AM10/1/19
to Google Apps Script Community
For persistent storage in the client side, you can store values in the window.  That way, there is no need to call the server.

Click button to open picker
window.thePickerIsOpen = true;//Stays in browser until it is closed

Picker Opens
Picker is either Closed or a file is Selected
The pickerCallback runs

window.thePickerIsOpen = false;//Set to false

Your setInterval code checks window.thePickerIsOpen
Reply all
Reply to author
Forward
0 new messages