Before you continue reading the article, I would like to point out that it already assumes certain knowledge of Power Apps concepts.
There are currently several options in Canvas Apps to trigger certain logic when the application starts. We have App.OnStart
, App.StartScreen
and Screen.OnVisible
. Beyond that, there are a few settings associated with these formulas. How to make sense of all this? 🤯 And how should the data be loaded when the app starts? Let’s take a look.
Imagine a simple request approval application. We have two user roles – approver and requester. Both roles need common data to be loaded when they run the application – a list of request types, application styling and navigation menu items. In addition, each role needs to be redirected to a different initial screen – the approver wants to see a list-view of their approvals and the requester wants to see a list-view of their requests. Related to this is the need for each to load different data when the application starts – the approver will load the requests that are pending his approval and the requester will load the requests he has created.
First, let’s look at the simplest part. Where to load screen-related data? The first option is App.OnStart
. In order to load the data only if the user has a certain role, a condition similar to this would have to be added.
// App.OnStart =
Switch(
varCurrentUser.role,
"approver",
Set(varApprovals, Filter(Approvals, Approver = varCurrentUser.Email),
"requester",
Set(varRequests, Filter(Approvals, Requester = varCurrentUser.Email)
);
It will work, of course, but once there are more roles in the application and more requests to load screen-related data, App.OnStart
will be very messy. Besides, data that is only related to one screen is stored in a global variable, that’s not right either. Let’s try it another way. Let the data be loaded only in the Screen.OnVisible
formula for a specific screen. And instead of a global variable, let’s use a context variable so that the data is only available in the required scope.
// scr_Approvals.OnVisible =
UpdateContext({
ctxApprovals: Filter(Approvals, Approver = varCurrentUser.Email)
});
// scr_Requests.OnVisible =
UpdateContext({
ctxApprovals: Filter(Approvals, Requester = varCurrentUser.Email)
});
Next, we will look at where to decide what screen the user should be redirected to. Previously, the Navigate
function in App.OnStart
was used. This is now impossible due to the ‘Enable Navigate function in App.OnStart’ setting, which is disabled as recommended. Instead, the App.StartScreen
property is available in which the following evaluation can be performed.
// App.StartScreen =
Switch(
LookUp(Users, Email = User().Email).Role,
"approver",
scr_Approvals,
"requester",
scr_Requests
)
But here comes another problem, what if we want to store the user role in a variable for later use. This is not possible, because App.StartScreen
is not a behavioral formula, so we cannot use the Set
function. Neither can we set a variable in App.OnStart
and use it in App.StartScreen
, because App.StartScreen
doesn’t support global variables. Therefore, it is necessary to perform LookUp
twice, once to evaluate App.StartScreen
and once to store it in a variable. That doesn’t sound too good, does it? 🤨
Before I present the solution for the variables and App.StartScreen
, let’s take a look at how to retrieve data common to the entire application. Of course, this data should be stored in a global variable and we can use the App.OnStart
. Which would look like this.
// App.OnStart =
Set(
varApprovalType,
Table(...)
);
Set(
varNavigationMenu,
Table(...)
);
It looks good, but if you need to load large amounts of data, there will be a problem. It will take users quite a long time to start the application (see ‘Time to first screen’ in the application analytics report). However, this can be solved by enabling the ‘Use non-blocking OnStart rule’ setting. What this does is that it will run App.OnStart
and Screen.OnVisible
formulas in parallel when the app starts. If the setting is turned off, it always waits for App.OnStart
to finish before it starts evaluating Screen.OnVisible
– this is when the ‘Time to first screen’ is increased.
It almost looks like the ‘Use non-blocking OnStart rule’ will save us, but we might run into another problem. Let’s go back to our approval app and extend it with user groups. We want the approver to be able to see requests from other approvers in their group (e.g. HR). The user group should be stored in a global variable, so it can be used in other places in the application. Let’s do the following.
// App.OnStart =
Set(
varCurrentUser,
LookUp(Users, Email = User().Email)
);
// scr_Approvals.OnVisible =
UpdateContext({
ctxApprovals: Filter(Approvals, Approver.Group = varCurrentUser.Group)
});
Do you see the problem? 🤔 scr_Approvals.OnVisible
depends on the varCurrentUser
variable that is set in App.OnStart
. But! scr_Approvals.OnVisible
and App.OnStart
are evaluated in parallel, so we may have a situation where scr_Approvals.OnVisible
starts evaluating and varCurrentUser
doesn’t contain data yet.
To give you an idea, I am attaching my little experiment 🧪
[8:02:38] App.OnStart: Entering
[8:02:38] App.OnStart: Fetching data
[8:02:38] Screen.OnVisible: Entering // Screen.OnVisible is being evaluated before App.OnStart has finished
[8:02:38] Screen.OnVisible: Fetching data
[8:02:40] App.OnStart: Data fetched // continue to evaluate App.OnStart
[8:02:40] App.OnStart: Leaving
[8:02:40] Screen.OnVisible: Data fetched
[8:02:40] Screen.OnVisible: Leaving
Finally, we come to the StartUp screen pattern that aims to solve most of the mentioned problems. This pattern is based on omitting the App.OnStart
formula, thus reducing the ‘Time to first screen’ to a minimum. Instead, a new screen scr_StartUp
will be created, which will be set as App.StartScreen
. All common variables will be set in the scr_StartUp.OnVisible
formula. The advantage is that at this point the app is already loaded and even though the data is still loading, you can already show some part of the interface to the user. Once everything in scr_StartUp.OnVisible
has been processed user must be redirected to the actual application screen. Unfortunately, you cannot use the Navigate
function in Screen.OnVisible
either. So you have to do something else. Fortunately, members of the PowerApps community 💜 have already figured this out – just use Timer
named tim_StartUp
, which has following configuration.
App.OnStart
property in the settings 💡// scr_StartUp.OnVisible (last line!)
UpdateContext({
ctxStartUpTimer: true,
ctxStartScreen: scr_Approvals
});
// tim_StartUp.Start & tim_StartUp.AutoStart
ctxStartUpTimer
// tim_StartUp.Repeat & tim_StartUp.Reset & tim_StartUp.Reset
false
// tim_StartUp.OnTimerStart
UpdateContext({
ctxStartUpTimer: false
});
Navigate(ctxStartScreen);
To make this pattern clearer I am attaching a diagram.
To make it easier for the user to work with the application, don’t forget to add indicators on scr_StartUp
that the data is still being loaded. Such as progress overlay.
Let’s quickly return to the problem with App.StartScreen
. This can be solved very easily using the StartUp screen pattern. Just modify the above code to the following. This allows us to use global variables when selecting the intial screen.
// scr_StartUp.OnVisible (last line!)
UpdateContext({
ctxStartUpTimer: true,
ctxStartScreen: Switch(
varCurrentUser.Role,
"approver",
scr_Approvals,
"requester",
scr_Requests
)
});
This design pattern therefore helps to solve the problem of loading data when the application starts. Let’s summarize its advantages:
- Application starts very quickly (minimizing the ‘Time to first screen’ )
- Better code layout – we no longer have
App.OnStart
,App.StartScreen
andscr_Initial.OnVisible
, but onlyscr_StartUp.OnVisible
andscr_Initial.OnVisible
- Cleaner code – setting the global variables in
scr_StartUp.OnVisible
and everything else only on the specific screens
Finally, I would like to recommend that while creating a new application, start by implementing the StartUp screen pattern. This will make the work that would be required for later modifications easier. The exceptions, of course, are applications with only one screen.
A template using the StartUp screen pattern is available on this link.
🫧 Bubble out! 🫧 and thank you for reading and sharing this article 💙
About the Author
Hello there! My name is Adam Hrouda.
I am a developer and backpacker from Czechia living in Dresden, Germany I have created this website so I could share my thoughts, ideas and concepts.
Currently, I am working at DataBrothers as a consultant and software developer.
References
Hrouda, A., (2023), ‘StartUp screen pattern in Canvas Apps’, available at: https://www.adamsbubble.com/posts/startup-screen-pattern [accessed 25th March 2024].