It’s always a compromise to use a progress bar, as it’s usually not known how long something will take, and therefore how to plot progress. This is especially true in Apps Script when the activity is happening on the server, disconnected from the client side that is trying to report on its progress. In addition, server side activities don’t tend to have many break points, since they are synchronous.

In today’s post, I’ll show you how to create a fairly smooth material design type progress bar that runs client side and reports on things that are happening client side. For the example, I’ll use an updated version of the code described in A webapp to share copies of the contents of folders. Although there’s a fair bit of code here, and some of the problems around asynchronicity and polling are quite challenging, most of it is boiler plate.

It looks like this

With a discrete progress bar at top of screen, a spinner, and also the capability to return arbitrary objects which can be used to report on the status of things. The example here is able to update the table with the status of copying files at the same time as drawing a progress bar.

You can get it to copy itself to your drive using http://goo.gl/p3Ixbl

How it works

I’m using this very simple nice bar renderer on the client side – http://ricostacruz.com/nprogress/

On the server side, cache is used to store progress as the activity is looped through. The normal server side loop activity contains some code to write some progress info at every opportunity, and is shown in red. This is interrogated from the client side, which passes (the item parameter), the latest status update it saw. Like this, data can be persisted across asynchronous client/server calls. Note that the server side doesn’t return the status update (it would be too late as it would be finished by then). We’ll look at how the client side gets that later.

Note that progress is a number between 0-1 that shows how far through the task the server has got. But if there is only one or two files to copy, it wouldn’t be possible to show a smooth progress on the client side from only a couple of data points. That’s why the min and max values are also given, and they tell the client that this report lies somewhere between min and max. When the client retrieves this status report it knows the range it should be in by using min and max, and adjusts it’s plot rate according to how long it’s taken to get this far versus how long we still have to go, which it can deduce from the min and max.

There are a couple of other things needed on in the Server side to manage creating the status reports. None of this needs modification unless you want to add extra fields to communicate.

as well as this namespace, which manages cache.

Client Side

The client side polls the Server to ask for status updates according to its own schedule, and plots the progress bar, also to its own schedule, until it detects a change from the server side from which it can make a better estimate of the finish time. It uses ifvisible, to ensure that its only bothering to poll if anybody is actually looking at it. None of this needs changed either, unless you want to change the polling frequency, which is controlled here

Client side polling

Controlling the progress bar

This namespace dynamically smooths the progress bar- given that the server updates are not going to be very regular, and shouldn’t need any tweaking. You can see here how the item.max and item.min are used to make sure that the progress bar stays in reasonable bounds, and how the estimated overall duration is adjusted by how long things have taken so far.

Initializing the server side progress

This creates a progress recording environment on the server side. It of course happens asynchonously. I use my own Provoke.run to do this, but you can of course use google.script.run as well.

Starting and stopping the progress bar

In my App, the progress bar kicks off whenever the user hits ‘copy’, and the progress related code is shown in red

Extra parameters

You’ll notice that I’m dynamically updating the table with which file is currently being copied.

That’s because the progress process can also be used to persist other data in addition to progress data. Back in the server side function that is being measured, I’m maintaining an array – activeFiles. This is being used to communicate all the files as they get done.

And back on the client side,at each polling event, I just do this to report on the file status in my table

The code

You can get your copy delivered to your Drive with the webApp using http://goo.gl/p3Ixbl

This blogpost gives some more info on setting up for your own folders.

For more like this see Google Apps Scripts Snippets
Why not join our forum, follow the blog or follow me on Twitter to ensure you get updates when they are available.