In the last post, I showed how to create and move DOM elements dynamically. In this post, we’ll look at a great use case for that functionality — using loading images to improved the perceived responsiveness of the page.
Dojo in XPages Series
Dojo in XPages — All Blog Posts
Why use loading images
You’ve undoubtedly seen applications where you click (or swipe) to trigger some action or data load and you then see some type of animated image that indicates that something is loading or processing. This is a common convention to convey to the user that something is happening. If it takes 10 seconds to respond, but the user receives that indication that something is happening, it will appear to be much more responsive than clicking a button and waiting 10 seconds without any indication that the desired action was triggered.
If the user doesn’t receive feedback very quickly, they may click again (multiple times) or leave the page altogether and assume that something is broken.
But this perceived responsiveness can be easily improved with the use of an image that shows the user that their action was triggered and something is happening. This can go a long way toward improving users’ perception about your application.
Places to use loading images
There are two ways that I’ve seen these images commonly used.
- Use the image to replace the data that is being loaded, in order to indicate that the data is being updated.
- Use the image to replace the button that was clicked, in order to show that the action is underway (and to prevent the user from clicking it again right away).
In either case, when the action is triggered, you can use dojo to either hide or replace the data, displaying a loading image instead.
Examples
I set up an example XPage with a view panel that shows 1,000 rows, so there may be a bit of a delay when refreshing the page. I added 2 buttons that put the loading image in place of the view data and 2 buttons that put the loading image in place of the button.
The first button uses dojo.place() to both create an image tag and replace the body of the view panel with it. This displays the loading image (which is an animated gif, although you can’t see that by a static screen shot below) in place of the view data, so it’s clear that the data is being refreshed.
dojo.place('<img src="http://www.fluendo.com/media/images/loading_gif.gif" />', dojo.byId("#{id:viewPanel1}"), "replace");
The second button produces the same display, but in a different way. It creates the image and puts it before the view data, then hides the view data.
dojo.place('<img src="http://www.fluendo.com/media/images/loading_gif.gif" />', dojo.byId("#{id:viewPanel1}"), "before"); dojo.query('#' + dojo.byId("#{id:viewPanel1}")).style('display', 'none');
The third button replaces the button itself with a loading image, by creating the image tag and replacing the button with it.
dojo.place('<img src="http://www.xiconeditor.com/image/icons/loading.gif" />', "#{id:button3}", "replace");
The fourth button creates the loading image and replaces the button text with it, but using the innerHTML
property, putting the image within the button.
dojo.byId("#{id:button4}").innerHTML = '<img src="http://www.xiconeditor.com/image/icons/loading.gif" />';
Image Source
The examples shown above all include full URLs to some loading images online. I did this so you could easily test the code. However, I would strongly suggest adding the image to your application and referencing it relatively. Depending on your network latency and server performance, you may not even see the loading image if it takes longer to load than the data does! It’s much more effective to show it without a delay.
If the image is in the application and still not loading quickly enough, you can try to pre-load it onto the page and hide it, so that it’s cached.
Additional Thoughts
You can combine these techniques and replace both the button and view body if you’d like. (Another option would be to use the loading image in the view body, but do something to change the styling of the button to show that it has been clicked.)
This will only work as expected if the page is either fully refreshed or if it’s a partial refresh that includes whatever you’ve replaced with the loading image. For example, if your partial refresh target is the view body, then the view data will refresh, but the button may not reload and will continue displaying as a loading image.
You can fix this by either including the button in the partial refresh area or by running code on load of the view panel to hide the loading image and re-display the button. Using the replacement-type display of the loading image would not be good in this case, because the original button would be gone.
