GAS UI - Menus and Side Bars
What is UI?
UI stands for user interface. It can refer to this in regards to function and also design. I'm not much of a designer so I am going to focus mainly on the functional side. If you want to read more about UI (and the difference between UI and UX), this article was helpful for me.
In GAS, developers have the ability to add UI function and design to the Google app's native UI. Therefore, when user's interact with your app or add-on, they may not realize when they are interacting with the native UI or your UI.
I've covered menus here so I'll try not to be too redundant.
One thing I wanted to add is that if you are developing and add-on, you can use .createAddonMenu('Your Menu') instead of .createMenu(). Also, if you are developing an add-on, be sure to read through the documentation on this, especially if you will need any authorizations for your scripts to run. These two menu methods act differently based on whether or not authorizations are required so if you are not getting the desired result, this may be why.
One UI feature that does not resemble native UI is the ability to turn an image into a button that runs a function when clicked. This comes in handy when your script needs to be run from a mobile device. Since this is well documented by Google, I'm going to just link to it.
The basics of the GAS side bar are pretty straightforward and can be found here. One bit of clarification, much of the UI cannot be triggered by clicking run in the GAS editor. They must be run on the client-side, meaning they must be run from within the app. This makes it difficult to test when you have a side bar that is multiple pages long or otherwise takes several steps to get to.
One way around this is to create function shortcut within the app. You can do this by creating a custom button with the respective function as the assigned script or to add it as a menu item. I like to use the menu option and create a test menu item. Then I assign that menu item to the function that runs the UI element I want to test.
Drop-down from items in sheet
In several of my projects, I have populated a sheet with some user info (e.g. list of user's calendars). In the side bar, I use a drop down (i.e. <select> tag) with the user info. When the user clicks submit, the info from the drop down then gets sent back to the server to be used in a function. In order to accomplish this, the html file needs to run a script to retrieve the info from the sheet.
It took me quite a bit of trial and error to figure this out and, to be honest, I don't quite understand it all perfectly.
Essentially, functions called from the client-side must be done like this: google.script.run.function(). The first function that runs is .calendarNameDropDown() (server-side) which returns an array of the names of all the user's calendars. Then, upon successful execution of that function (hence .withSuccessHandler()) another function is run (client-side) that creates a text list containing each calendar name and adds each name as an option to the <select> tag with the id "calendar_name".
The next section is the function that is run when the user clicks next (i.e. submit). Because I want to do something other than submit the form when the user clicks next, I use .preventDefault() on the event listener. Otherwise, I would not be able to run any other functions when the user clicks next. When clicked, the selection from the drop down is sent back to the server via .calendarName(this).
Side Bar Loader
Adding a loader to your side bar can give it a really nice touch for those scripts that take a little longer to execute. I have found that without some sort of loading screen, the user may not be able to tell that the script is running. The html file below shows an example of a loading page that I have used in several projects.
While reading through some forums about this, I noticed that some users had a difficult time figuring out how to close the loading page once the script execution was complete. Because GAS is asynchronous, what seems to work for me is to call the function of the loading page and the long function upon submission of the previous page and call the function of the next page in my side bar at the end of the long function. So it looks like this: user clicks submit > call longFunction() and loadingPage(); once complete, longFunction() calls nextPage().