An application that gives feedback helps the user understand what it is doing. Single page applications tend to do a lot of stuff in the background – like communicating with a server.
The background stuff is invisible to users – it therefore makes sense to show the user that some background magic is happening.
Often, the same mechanisms are involved from the start of an action to its result. For those mechanisms you can set up a feedback cycle.
A feedback cycle can look like this: Validate the user’s action. If the action is not allowed, instantly show the reason. Check whether it is a critical action that has a bigger impact – like deleting an item – and if so, let the user confirm that he really wants to perform that action. As soon a the action takes place, let the user know that the action has started and show its progress. This is especially important for actions that are executed asynchronously in the background and need some time. When the action has finished, let the user know the result. Then the feedback cycle is complete.
Constant feedback guides the user through your application and improves the general user experience. It also gives him the confidence that he can not mess up things by accident e.g. deleting important data because of clicking the wrong button by accident. To improve user confidence, it is important to make sure that the feedback cycle is implemented consequently for all views and actions. As an example, I am going to describe the feedback cycle that is used in our product Relution.
Validating if an action is allowed
The Relution Web UI has a lot of forms. In most cases, the input has to match certain criteria. We are displaying that criteria next to the form to let the user know what valid input should look like. Especially for complex criteria (as you can see in the example below) it makes sense to show this information instead of only showing that the input is invalid.
The only disadvantage of this approach is that you have duplicated validation logic because the input has to be validated on the server as well. Validation in the application must not replace server side validation.
Another example where we are making a validation are our action buttons. When the user is not allowed to perform a certain action, we disable that button and show a tooltip why the action is not allowed.
Our first approach was to simply hide the button when an action could not be performed. Later, we decided that it is better to show all buttons so the user always knows what kind of actions are available. All buttons that can not be used are disabled. The problem hereby was that it was sometimes not clear why the button was disabled because of complex decision criteria evaluated by the application. The solution was to make the validation process visible to the user by giving him feedback why the button is disabled.
Confirmation of critical actions
Some actions need special attention by the user. Those actions should be explicitly confirmed by the user to prevent executing them by accident. There are two common situations: One is that the user wants to delete data and the other one is that the user is on a form and tries to leave it without saving the changes.
Both actions would result in an unwanted loss of data when executed by accident.
Look here for an example on how to implement a leave confirmation with AngularJS.
Progress of an action
We have several loading indicators to visualize when a request of the application to the server is being processed. The main loading indicator is placed below the menu. It is a generic indicator that is triggered every time any request performed. As soon as all requests are finished, it is turned off until the next requests starts – very much like the network activity indicator of your mobile phone.
Another loading indicator is placed next to our instant search box. Sometimes the server needs some time to process the search request so the results for the search query can not displayed instantly. The indicator gives the user feedback that a search request to the server is performed. It starts flashing as soon as the user enters text to visualize that the search is performed instantly and that the user does not have to press a search button or hit the enter key.
Then there is a page change loading indicator. When the user navigates to a another view, things like the view template and the data from the server to populate the template have to be fetched. During that time, an overlay locks the whole page and shows a loading spinner. As soon as all dependencies are loaded, it disappears and the new view is visible.
Result of an action
As soon as the action has finished, the user should be notified about that. When there is a server request, we are displaying a notification as soon as the request has finished. There are two cases: request was successful and request failed.
We are making requests to a REST API, so we are using different http methods like POST for creating a new item, PUT for updating it and DELETE for deleting it. We have a success notification for each http verb. So e.g. when a POST request was successful, we are showing a notification that the item was successfully created. The notification is visible for three seconds and then it will be closed automatically so the user won’t get annoyed of those success notifications. The user can also close those messages by clicking the “X” symbol.
Way more important are the messages that appear when a request to the server resulted in an error response. The thing about asynchronous requests to the server is that they are normally invisible to the user. Unless he open the browser’s development console, he will never know that the request failed – or even that it happened in the first place. In order to make failing requests visible to the user, we introduced error notifications. These notifications are mapped to different http response status codes. We are mapping the most common http status codes to a specific message. The image below shows an error notification that was displayed because the server returned a status code 500 ‘Internal server error’. Our goal as developers is to prevent any server errors but hey – things do happen and things do go wrong! For those error cases, we give the user a chance to directly report that error by adding a ‘Report Bug’ to the error notification. When the user clicks that button, we automatically send an email containing all the information we need to reproduce the bug.
With a feedback cycle, you can tell the user what is going on in your application. However, keep in mind that the applications’s feedback should not be too annoying. Remember Microsoft’s Office Assistant “Clippy the paperclip” used in previous Microsoft Office versions giving you suggestions all the time? Feedback should have an additional benefit for the user and not distract him. With meaningless or too much feedback you will make the user experience worse – so use it wisely.
Also make sure to use it consistently. Don’t break your own feedback cycle by forgetting to add it to certain actions or views. All in all, our customers are appreciating Relution’s feedback cycle – except for our bug report feedback modal, but we try our best that it will rarely be seen. If you are interested and want to see our feedback cycle in action visit relution.io and set up a trial account.