How to implement them and avoid unnecessary data traffic
OutSystems is very handy and offers a lot of ready-to-use UI patterns when it comes to quickly implementing reactive web applications. An example of this is the so-called UserInfo widget, which resides in the upper right corner of the page. Unfortunately, this widget does not implement the profile picture functionality although it displays a placeholder image.
Summary
In this article you will learn
- how to implement this missing feature in a simple way,
- where there are drawbacks regarding data traffic,
- and how to avoid them.
Therefore, we will build a small example app together.
What you need
If you want to follow up the implementation on your own, you need:
- An OutSystems account (a free personal environment is sufficient)
- OutSystems Service Studio
- A web browser with dev tools to inspect sent requests (e.g. Edge, Chrome, Firefox)
For this tutorial you should already have some experience in building reactive web applications with OutSystems.
The simple solution
Adding a profile picture to our users
In OutSystems, end users are managed in the User entity that can be found in the System module and is by default added as a dependency of new reactive web apps. Since this entity does not provide an attribute to store a profile picture, we need to store the picture elsewhere. In an application intended to run in a production environment, we would consider a separate domain-based service for this type of user profile data or obtaining the profile image from an identity provider such as for example Azure Active Directory.
To keep things simple in this article, we create a separate UserPicture entity in our example application. Since each user can only have exactly one profile picture, we use User Identity as the primary key for UserPicture so we get a one-to-one relationship.

For the user to be able to change the profile picture, we need a form with a data action GetProfilePicture to load the current image data.

Next, we place an upload widget on the form. By setting the widget’s parameters File Content to GetProfilePicture.Picture and Accept to Image, we get a neat editor which shows the current picture and provides an option to upload a new image file.

As you can see in the screenshot above, a handler for the On Change event is added to the widget as well. This is to directly save the image to the database when the user selects a new file. To realize this functionality on the server side, we implement a new server action ProfilePicture_Save.

For better testing purposes, we will also add a server action to remove the profile picture if one exists. Therefore, we can reuse ProfilePicture_Save and set the parameter Picture to NullBinary(). To update the ui afterwards we could refresh the data action GetProfilePicture. But to save this server callback, we can simply be optimistic and overwrite the value as it is expected to be NullBinary().

After we have this all set up, we can publish and test our application.
Displaying the profile picture in the UserInfo widget
For the moment, the user can already change the profile picture, but of course it will not be displayed in the UserInfo widget in the upper right corner yet. To realize this, we need to extend the UserInfo widget accordingly. An uncomplicated way would be to add the already implemented data action to the widget and configure its output parameter to be the source of the image widget. The disadvantage of this method is that it would be reloaded on every page load and thus the profile picture would always be reloaded from the database and transferred from the server to the client. As the title of my article states, we want to avoid unnecessary traffic, so this is no solution.
If you look at how OutSystems loads the username from the server and displays it in the UserInfo widget, you will see that they store the username in a client variable and request it from the server only when necessary. So why shouldn’t we also store the profile picture in a client variable? This poses the problem that OutSystems does not support the binary data type for client variables. If you search for a solution to this issue in the OutSystems community, you will find a simple solution that encodes the image as base64 and stores the resulting string in a client variable. To display the image, the string is then decoded to binary data again.
So, let’s put it this way for now. To save another request to the server, we simply extend the existing server action GetUserNameFromServer by another output parameter for the profile picture. Of course, we need to extend the client action GetUsername as well and store the received profile picture locally into a new client variable UserPicture. For better reusability and maintainability, we implement this as a separate client action to store the profile picture on the client side.

Obviously, we also need to retrieve the locally stored profile picture and load it into the source parameter of the image widget of UserInfo. For this we use a second client action GetLocalUserPicture which is configured as a function. This allows us to modify the parameters of the image widget as shown in the figure below and directly receive the picture from the client action.

For encoding and decoding the binary data as base64 string we can simply write our own javascripts Base64encode and Base64decode. These contain one input and one output parameter to receive and return the binary data and the encoded string, respectively. The conversion is pretty easy to do with the built-in btoa and atob functions of the window object in javascript:
// base64 encode:
$parameters.Base64 = window.btoa($parameters. Binary);
// base64 decode:
$parameters.Binary = window.atob($parameters.Base64);
Congratulations, we have managed to let the user upload a profile picture and display it in the already existing UserInfo widget without having to request it repeatedly. But there is even more to the story…
Is using client variables a clever idea?
Client variables differ from normal screen variables by being kept in local storage even when the browser is closed, and by being shared between screens. This is especially useful if you want to preserve user preferences or an overall context.
This is great for our purpose, isn’t it? As long as client variables are only used on the client side, the solution described above works totally fine.
Unnecessary data traffic in server callbacks
However, as soon as a single client variable is accessed on the server side, all client variables are transferred to the server with each callback by default.
To illustrate the behavior in our sample application, let’s create a client variable called ResultsPerPage with a default value of 10 and add a small list view to our screen. For simplicity, the data action GetListData returns n randomly generated passwords, where n is the value of ResultsPerPage.

If we now publish this new app version we can check, in the developer tools of our browser (to open press F12), which data is sent to the server when we click on the Refresh list button. As you can see in the network tab, all client variables, including the base64 encoded profile picture, are sent within the payload of each server callback.

Certainly, 102 kB as in this example is not a large amount of data but transferring it unnecessarily does not make sense. Depending on the complexity of the application and the number of client variables that are only required locally, this can quickly add up to quite a bit of data that should not be transferred.
The better solution
The goal is to prevent the profile picture from being sent to the server, as part of the client variables, with each request. To achieve this, we can modify our already implemented client actions to store the picture in a separate local storage item that is independent of the standard OutSystems mechanism, wich also utilizes the local storage for its client variables.
To do this, we first remove the UserPicture client variable, since we won’t need it anymore. Afterwards we need to adjust the logic of both client actions SetPictureFromLocalStorage and GetPictureFromLocalStorage as shown in the following figure:

As you can see in the middle section of the screenshot, all three new JavaScripts have an input parameter called AppName. It is used to create an application specific prefix for the key of our separate local storage item. This ensures each app gets its own namespace if multiple apps are deployed on the same host. In addition, the prefix also contains the segment $KeepLocalVars$ to identify our purely local variables and distinguish them from the namespace used by OutSystems.
To access to the local storage, you can find the component Local Storage Reactive by Paulo Cação in the OutSystems forge. I decided not to use it, since we only need three simple lines of code to achieve the result and can do the required encoding of the binary data at the same time.
Below you can find the listings of the three new JavaScripts:
// SavePictureToLocalStorage
window.localStorage.setItem(
'$' + $parameters.AppName + '$KeepLocalVars$UserPicture',
window.btoa($parameters.Binary)
);
// RemovePictureFromLocalStorage
window.localStorage.removeItem(
'$' + $parameters.AppName + '$KeepLocalVars$UserPicture'
);
// GetPictureFromLocalStorage
var p = window.localStorage.getItem(
'$' + $parameters.AppName + '$KeepLocalVars$UserPicture'
);
if (p!==null) $parameters.Binary = window.atob(p);
Let us now republish our app and inspect the network tab. As you can see, now the client variable UserPicture does not get sent to the server anymore.
One last question
How does the local storage item get cleared when the user logs out?
The answer is simple: Never!
The reason you cannot encounter an issue with this behavior is, that OutSystems clears the client variables on logout, so Client.Username is empty the next time GetUsername runs, and the locally stored profile picture will be overwritten. Nevertheless, it is good practise to actively remove the profile picture from local storage on logout. To do this, we just need to call SetLocalUserPicture with the parameter Picture set to NullBinary() in the Logout client action of the UserInfo widget:
