In the last WTF episode I shared how to build URLs to open forms and views in model-driven apps using environment variables.
Now I did say that I would next cover Power Apps Cards towards the end of the WTF episode but I came across a bug 😓 which I reported and the fix is going to be rolled out (maybe by the time this blog post is published). I had to pivot and brought this episode forward.
This time round, I’ll share how to open model-driven app forms and views from a canvas app in a model-driven app within Power Apps mobile. Switching from canvas apps to model-driven apps in Power Apps mobile is so simple. This is achieved by using deep links inside buttons in canvas apps using Environment Variables. There can be use cases where you want to direct users from a canvas app, to the data in a model-driven app form or view.
The technique is similar to what I shared in the last WTF episode except this time, the Environment Variables are being referenced in PowerFx, rather than cloud flow expressions.
Breaking down deep links for model-driven app forms or views in Power Apps mobile
The base query parameters are similar to what I shared in the last episode with minor differences. All of these base query parameters can be created as Environment Variables in a solution.
1. The first query parameter is targeted-app.
To load any model-driven app, the query parameter value is ms-apps as outlined in the Microsoft Learn documentation. Create an environment variable with ms-apps as the current value.
2. The second query parameter is org-url.
This is the Dataverse environment URL without the https, colon and forward slashes (://)
Create an environment variable with the Dataverse environment URL as the current value.
3. The third query parameter is the appid.
In a solution create an environment variable for the app-id query parameter value.
You can find the appids of your model-driven apps by using the GET request I showed you in the previous WTF episode and copy the appmoduleid value and paste it into the environment variable.
The fourth query parameter is the tenant id of the environment where your model-driven app lives in.
In a solution create an environment variable for the tenant id. The tenant id can be found by navigating to make.powerapps.com, click on settings on the top right and select session details. Copy the tenant id and paste the copied tenant id into the environment variable.
Putting it all together with the form or view query parameters - it’s the same as what I covered in the last WTF episode. For a form it’s the following where the pagetype is entityrecord and the query parameters of the Challenges table logical name and ID of the challenge are included.
For a view it’s the following where the pagetype is entitylist and the query parameters of the Challenges table logical name, view id and viewtype are included.
Building deep links in Power Apps studio
Next, let’s understand how to build the deep links for the Power Apps mobile app in Power Apps studio. First, make sure you have the Dataverse tables of Environment Variable Definition and Environment Variables Values added as data sources.
To keep it simple for this episode, I’m using two screens and the design is very basic. The first screen is a gallery that displays all active challenges from Dataverse.
The second screen displays some data from the Challenge selected in the gallery.
There are two buttons in this screen which is the same as the two hyperlink I showed you in the last WTF episode.
The first button, Edit Challenges, will open the form for the selected Challenge.
The second button, View Active Challenges, will open the view for the Active Challenges system view in the model-driven app.
Several expressions and functions used in PowerFx
In the OnSelect property of the button, by default it will be false. I’ll use PowerFx to build the URL to open the form and view in the Power Apps mobile app for the model-driven app.
There's several expressions and functions I'm going to apply in PowerFx.
String interpolation
What I’m going to do is concatenate the Environment Variables and string values to build the deep link. I’ll use string interpolation that came into support in April 2022 instead of using the concatenate function or ampersand character in PowerFx.
As per the Microsoft Learn documentation, "Prefix the text string with a dollar sign $ and enclose the formula to be embedded with curly braces { }."
This is what will be applied in PowerFx to create the address for the Launch function.
➡️ If you want to learn how to use string interpolation, check out this awesome blog post by Matthew Devaney, another Microsoft MVP in our community who covers it in detail.
Launch function
To open model-driven apps in Power Apps mobile, use the Launch function for the deep link. There’s three parts to the function,
address which is mandatory
parameters and target is optional
I’ve found that parameters is not needed in the function as the query parameters for model-driven app forms and views are part of the address.
I also found that target is also not needed in the function as it’ll open the model-driven app in the Power Apps mobile app without providing a target. So address is the only one I’m using in PowerFx to build the URL.
LookUp function
To reference Environment Variables in PowerFx, the key thing to understand is to
Retrieve the Environment Current Value
Where the parent record equals the Environment Variable you're after
Underneath the hood in Dataverse, there's two tables in Dataverse.
Environment Variable Values - this is where the current value of an Environment Variable lives
Environment Variable Definitions - this is the "parent record"
For example, for the first parameter of targeted-app, the Environment Variable current value needs to be retrieved. To achieve this, retrieve the current value from the Environment Variable Value table that is associated to the Environment Variable Definition that equals the target-app parameter.
We can use logic in PowerFx to retrieve the current value where the Environment Variable Definition equals the target app Environment Variable.
You can watch this part of my video where I explain this in detail for your understanding.
What the PowerFx formula looks like
Open model-driven app form
For the OnSelect property of the Edit Challenges button in the canvas app, the following is what the PowerFx formula will look like for opening a model-driven app form in Power Apps mobile.
The Launch function is first referenced, followed by string interpolation, which starts with the dollar sign character and double quote, followed by the functions and formulas being delineated by curly braces. To complete the string interpolation, use a double quote. Then, to complete the Launch function, use a closing bracket.
This is similar to what I covered in the last WTF episode, and in this episode the Environment Variables are being referenced in PowerFx, rather than cloud flow expressions.
The minor difference in PowerFx when referencing the ID (Dataverse GUID) of the Challenge row is to use an expression that retrieves the ID from the selected Challenge in the gallery (from the first screen in the app).
Open model-driven app view
For the OnSelect property of the View Active Challenges button in the canvas app, the following is what the PowerFx formula will look like for opening a model-driven app system view in Power Apps mobile from a button in canvas apps.
It’s mostly the same with the only difference of changing the pagetype to entitylist and referencing the viewid environment variable along with providing the viewType definition of 1039 for system view. As a reminder, I did cover this in my last WTF episode so check out that episode if you haven’t already done so.
And action!🎬 Open the form or view in model-driven apps from canvas apps in Power Apps mobile
I'll open the canvas app on my mobile phone, and select a Challenge from a gallery.
After the Challenge loads, I'll tap on the Edit Challenges button in canvas apps and it'll open the Challenge in the model-driven app in Power Apps mobile. Awesome sauce!
I'll go back to the canvas app, select a Challenge from the gallery again, and tap on the View Active Challenges button. It'll once again open the Challenge in the model-driven app in Power Apps mobile. Pretty cool 😎
Summary
In canvas apps, you can use Environment Variables in PowerFx to build deep links to open forms or views in model-driven apps within Power Apps mobile. This allows users to switch from canvas apps to model-driven apps with one tap/a single tap 🤳🏻
Hope you learnt something new 😊 and stay tuned for the next episode where I'll cover how to do the same in Power Apps Cards - pending bug being fixed 🤞🏼
In 2020 I published a WTF episode that shared how to create a dynamic record URL for a model-driven app. This was to replicate the built-in functionality of classic workflows of creating a Record URL. It's typically used in use cases where you require a user to click on a hyperlink to load a row or view in a model-driven app.
The flaw with the method I shared is that it's using the Dataverse List Rows action to retrieve the appid query parameter value from the table called "Model-driven apps." This meant that the action needed to be included in all cloud flows that required a dynamic record URL for Dataverse or Dynamics 365. Not ideal as each action consumes an API call. Check out Jerry Weinstock's blog post that briefly covers what counts as an API call. Otherwise refer to the Microsoft Learn documenation.
Use Environment Variables instead
Environment Variables is a Power Platform feature that can be referenced in Power Apps and Power Automate cloud flows. They allow you to store and manage multiple values that can be used within your cloud flows as dynamic content inputs.
For reusable URL inputs, this is where Environment Variables are used rather than hard coding your URLs.
They enable you to move your configuration data from one environment to another with solutions.
If the value is different in another environment, simply change it one place in the Environment Variable.
These are two of many reasons as to why Environment Variables are useful when you need to dynamically create a URL for Dataverse or Dynamics 365 in your cloud flows.
In this WTF episode I share how you can use Environment Variables to build a URL to open forms and views in model-driven apps with the help of Power Automate cloud flows.
Model-driven app URL deconstructed
Let’s breakdown what parameters are used in a model-driven app URL.
For forms
URL for a form when using the appname query parameter. This is used in this WTF episode.
1. The Organisation URI which is the Dataverse or Dynamics 365 environment organization URL.
2. To open a specific model-driven app, use the query parameter of either appid or appname.
URL for a form when using the appid query parameter.
The appid is the ID of the app.
The appname is the Unique Name of the app. This is defined when the model-driven app is created and you can find it in the settings of the app.
You can use either as the query parameter however please note that when using the appid query parameter, the value will need to be updated in the environment variable with the ID in the target Dataverse or Dynamics 365 environment after deploying the solution with the environment variable. This is because the ID will be unique in each Dataverse environment.
For this reason, I’ll stick with appname as the query parameter and the uniquename value will be used in my URL. The appname remains the same in each Dataverse environment.
3. The value of the appid or appname query parameter.
The easiest way to retrieve these values is to query the Dataverse web API by using the following GET request.
You can perform this request directly in your browser and the values for the appid and appname parameters will display in the response. Note: based on your signed in user account, you will only see apps you have access to as defined by your security role.
In this WTF episode, I will be using appname as the query parameter.
4. The pagetype query parameter which defines whether to load a form for a row in a table, or a view of a table. For a form, the pagetype query parameter value is entityrecord.
5. The query parameter of etn which is the logical name of the table.
You can find this by browsing to make.powerapps.com, view the table in your solution, navigate to Tools under Table properties and select copy logical name. The copied value can then be pasted into a current value of an environment variable.
6. The GUID of the row in Dataverse or Dynamics 365. If you’re opening a form, the query parameter of id is required which is the GUID of the row in Dataverse.
7. An optional query parameter is the formid of the form in the scenario where you have more than one form for the table.
This can be found in the Form configuration settings within the table in a solution.
For this WTF episode, there’s only one main form for the Challenges table so I won’t be providing this parameter value.
For views
If you’re opening a view, the difference is that for number 4, the pagetype query parameter value will be entitylist.
For number 6, there’s the query parameter of viewid which will be the id of the view.
You can find this by navigating to the view in the model-driven app and copy the viewid value in the URL.
And lastly number 7, the viewType query parameter defines the type of view to open. The parameter value can either be 1039 for a system view or 4230 for a personal view.
Create environment variables in a solution
Now that we know the different components of the model-driven app URL, I'll next share how to create environment variables in a solution.
In a solution, create four new Environment Variables where the data type is text and the values are stored as a Current Value.
1. Organisation URI
The first environment variables is for the Organisation URI. To create an environment variable in your solution,
Click New and select more and then select Environment Variable.
Enter a Name for the Environment Variable and a description.
In the Data Type dropdown field, select Text.
Next add a current value which will be the Dataverse or Dynamics 365 environment URL.
Then click Save. The environment variable is now created.
2. appname query parameter value
The second environment variable is for the appname parameter value with a current value of the appname for the model-driven app. In my use case it's the Innovation Challenges model-driven app.
As a reminder, for this WTF I am using the uniquename value of the app which you can find through the GET API request I shared with you earlier in this blog post.
3. etn query parameter value
This is the logical name of the table. In my use case it's the Challenges table.
This will be the copied value from the table properties I shared with you earlier in this blog post.
4. viewid query parameter value
This is the id of the view. In my use case it's the Active Challenges system view.
🗒️Side note: use default or current value?
Some of you may be wondering, which method to use for storing a value in Environment Variables - Default or Current Value? 🤔
In my experience, current value has been used in projects because before Environment Variables came along, us consultants (or implementors - whatever you want to call us 😉) have become accustomed to having variables as "configuration records" with the value (such as GUID of a row) in target environments. The concept of a default value didn't exist beforehand and is different to the deployment pattern we've followed as part of solution deployment.
However there's nothing wrong in using the default value field in the Production/Live environment or using it across several environments AS LONG as the value is the SAME across all environment.
Please also keep in mind that each time you perform an export of a solution with the environment variables from a source environment (such as Development environment), you do need to remove the current value from the solution first. So this would be a pre-deployment task.
Build the URL in a cloud flow to open a form
The use case is when a new challenge is created in Dataverse, post a notification in the app and post message to a channel in Microsoft Teams that allows the user to view the newly created challenge record in the model-driven app or the active challenges system view.
In my cloud flow I have the add a new row Dataverse action for the Notifications table to create the in-app notification and I’m referencing the environment variables in the URLs for the actions. If you want to know how to create in-app notifications, refer to this WTF episode.
The other action is the Post a message to a channel in Microsoft Teams which has two hyperlinks, view challenge and view active challenges. When a user clicks on either of the hyperlinks, it will open the form or the system view based on the URLs. I'll next cover through the steps on how to build the URLs using the environment variables.
In the Microsoft Teams action, select the edit HTML button. This will switch it to the HTML editor.
For the View Challenge hyperlink, I’ll replace the placeholder URL value and build the URL using environment variables, followed by selecting the Dataverse environment URL environment variable.
Then select the Innovation Challenge app environment variable for the appname query parameter.
Next, enter the pagetype query parameter of entityrecord, followed by the Challenges logical name environment variable for the etn query parameter.
Finally, select Challenge as dynamic content from the trigger for the value of the id parameter. This will be the GUID of the row created.
Build the URL in a cloud flow to open a view
The first two steps are the same building a model-driven app view URL, the differences are
the pagetype query parameter is entitylist
the viewid query parameter is required which is the id of the view
the viewtype query parameter which is the definition of the view - either a system view which is 1039 or a personal view which is 4230
Save the cloud flow and it's ready to be triggered.
Demo
To trigger the cloud flow, I create a new row/record for Challenges in the Innovation Challenge model-driven app.
The in-app notification will appear in the model-driven app, and the hyperlinks when clicked on will direct the user to the Challenge form to view the newly created Challenge, or the Active Challenges system view.
The same experience is encountered when viewing the message posted in the Microsoft Teams channel.
Summary
Environment Variables are incredibly useful for automating processes where you need to build URLs through out your cloud flows to open a specific form or view to enter or update data in your model-driven apps. Create them once, and reference it anywhere in a cloud flow. However you do need to remember the following when using Environment Variables:
Add a current value in the target environment after deploying the solution
Remove the current values from Environment Variables prior to deploying the solution
Stay tuned for the next WTF episode as I'll share how to build URLs in Power Apps Cards - the next evolutionary step for "adaptive cards" 😎
Chances are you've landed on this blog post because you've searched for how to automatically refresh a rollup field. You're in the right place as this is what I cover in this this #WTF episode vlog.
What is a rollup field?
Rollup fields first came out in Dynamics CRM 2015 and there’s a couple of good blog posts by Jukka Niiranen, another long time Microsoft MVP in our community.
This talks about about how it works underneath the hood.
So what is it?
It’s a field that is an aggregated value of child records in Dynamics 365 and Dataverse. The supported functions are SUM, COUNT, MIN, MAX and AVERAGE.
Now the key thing here as mentioned in Jukka’s blog post is that a rollup field is refreshed every hour, but also is mass calculated 12 hours from when the rollup field was created or updated. This means it’s not performed in real-time. There are some use cases though where you do need it to be refreshed in real-time.
If you've searched on how to automatically refresh rollup fields, most of the answers say to use plugins or even a custom workflow action which requires code. If you know code, no problem.
With cloud flows, it’s straight forward to do and stick around till the end of this post because I’ll tell you whether it’s worth going through this effort with cloud flows.
Disclaimer
Now before we dive into how to refresh rollup fields with cloud flows, this is already blogged about by another person in New Zealand. His name is Boru Wang, go check out his blog. I’m still going to cover it in this episode with some differences to his blog post. I’m going to share two different methods using cloud flows that you can follow.
The CalculateRollupField function in the web API
The way to refresh rollup fields outside of plugins and custom workflow actions is to call the CalculateRollupField function in the Dynamics 365 and Dataverse API.
Quick break here to understand what is a function in Dynamics 365 and Dataverse,
Functions… represent re-usable operations you can perform using the Web API.. to perform operations that have no side-effects. These functions generally retrieve data and return either a collection or a complex type. Each of these functions has a corresponding message in the organization service.
The first one is Target, which is the table the rollup field lives in. This value is the EntitySetName of the table.
The second one is the FieldName, what is the logical name of the rollup field.
What this Microsoft Learn documentation doesn’t tell you, is that you also need to provide the GUID which is the global unique identifier of the row in the Target table, in order for the rollup field in that row to be refreshed.
This basically explains that because the calculaterollupfunction requires a reference to an existing row, you need to provide the GUID for that row in the table the rollup field lives in, hence the Target parameter required.
The GET request to call CalculateRollupField function
So let’s breakdown this GET request for your learning. To keep it simple for this WTF episode I created a rollup field for the Account table that performs the COUNT function to show the number of contacts related to the Account through the Account Name lookup field.
What we need to build our GET request to call the CalculateRollupField function is the following,
1. The Organization URI which is the Dataverse or Dynamics 365 environment organization URL.
2. The EntitySetName of the table.
You can find this by browsing to make.powerapps.com, view the table in your solution, navigate to Tools under Table properties and select API link to table definition. Then search for EntitySetName and you’ll find it.
3. The GUID of the table row for the rollup field to be refreshed in.
4. The logical name of the rollup field.
This can be found in the Advanced properties of your column that represents the rollup field in make.powerapps.com.
That's it. We’ll be using the in-built HTTP connector of cloud flows to perform the request that calls the CalculateRollupField function.
Scenarios
Now that we know how to form our GET request, the following scenarios is what I cover for the two methods of automatically refreshing a rollup field.
Create a Contact where the Account Name lookup column is populated.
Create a Contact where the Account Name lookup column is not populated.
Modify a Contact by changing the Account Name lookup column from one account to another.
Modify a Contact by clearing the Account Name lookup column so that it no longer related to an Account.
Delete a Contact so that is no longer related to an Account.
Method 1 - single cloud flow
This is what my cloud flow looks like.
I have a trigger of when a Contact row is added, modified or deleted. In the Settings I also have a condition for this flow to only trigger when the Account Name field contains data. I don’t want this flow to trigger if the Account Name is not populated, in other words blank.
In the select columns field, I have the logical name of the Account Name field because I only want this flow to trigger when this field has been updated.
Next, I have an action that references my Environment Variable that retrieves my Azure Key Vault secret value from the Azure portal. This Azure Key Vault secret is used for the authentication in the HTTP request.
The following are a couple of links on how to use Environment Variable for an Azure Key Vault secret value.
The next actions is the HTTP request action where I'm using an application user which requires creating an app registration in Azure portal as the authentication for the API request to the web API. To learn how to do this, check out A Visual Guide To Power Platform Service Principal Setup by Matthew Devaney.
In my HTTP request I have specified the request method which is GET where we’re calling the CalculateRollupField function, followed by the URI that we walked through earlier, and then we have my authentication details.
I’m using another Environment Variable that contains the Environment URL for my Dataverse to use in the URI. The GUID of the account row/record is inserted as dynamic content, it's retrieved from the trigger response of the Contact, and the Azure Key Vault secret is inserted as a dynamic content value from my Environment Variable.
The following are references to what each of these authentication fields mean.
1 - Authentication is Active Directory OAuth to reference the app registration in Microsoft Azure portal.
2 - This is the Tenant ID from the app registration in Microsoft Azure portal.
3 - This is the environment URL of the Dataverse (or Dynamics 365) environment.
4 - This is the Client ID from the app registration in Microsoft Azure portal.
5 - The option to select is Secret.
6 - This is the Client Secret from the app registration and we're using the Environment Variable to retrieve the Azure Key Vault secret value.
Scenario 1 - Create a Contact record associated to an Account record
OK now we're ready to run through our scenarios.
This is what the Account looks like prior to the automation being executed, the Account only has 2 contacts and this is what is displayed in the rollup field.
Create a
Contact and select an Account, then save.
When we
review the run history, the rollup field on the Account is refreshed.
The Number of Contacts rollup field has refreshed and is now correctly displaying 3.
Scenario 2 - Create a Contact record with no association to an Account record
Create a Contact, then save.
The cloud flow is not triggered which is correct due to the condition we specified, which is to only trigger if the Account Name lookup field contains data.
Method 2 - Using Parent flows and Child flow to make the automation reusable
Before we proceed with the remaining three scenarios, I want to switch over to Method 2 which is using multiple cloud flows. Shout out to George Doubinski for suggesting this method which I agreed is much better than Method 1.
We’re using the concept of Parent and Child flows to make the refresh of a rollup field reusable. In other words if you have more than one rollup field in your Dynamics 365 or Dataverse environment, this method enables the child flow to be called by multiple parent flows. You build it once and it is reused indefinitely. Genius.
To use a child flow, create it within a solution. Select the trigger, manually trigger a flow trigger, and enter in your inputs of EntitySetName, TargetID and FieldName.
These will come from the parent flows so that this child flow can be called multiple times to perform the refresh of rollup fields across tables and rows.
The next two actions are the same from Method 1 however the difference with the HTTP request is that I’m inserting the output values from the trigger as these will come from the parents flows.
The last two actions will send a response back to the parent flow that called it.
OK let’s check out the parent flow. Here's the parent flow.
The trigger is the same as Method 1 and the last action is run child flow, which calls the child flow that refreshes the rollup field based on the parameters provided. These parameters come from the input values that we defined in the trigger of the child flow.
Scenario 3 - Modify a Contact by updating the Account Name field to another Account record
Modify a contact record by updating the Account Name to another account.
We can now see the parent flow has triggered and see the child flow succeeded.
Navigate to the account record and the rollup field has automatically refreshed. The number correctly increments by 1.
The limitation with this scenario? Even though the account for the contact has been updated and the rollup field is refreshed in this account, the rollup field in the previous account the contact was associated to was not updated. I’ll talk more about this towards the end of the blog post.
Scenario 4 - Modify the Contact record by clearing the Account Name field
Clear the Account Name to another account.
The parent flow does not trigger.
The limitation with this scenario is that even though the account lookup field was cleared, the account rollup field has not refreshed.
Scenario 5 - Delete the Contact record
Delete the contact. The parent flow does not trigger.
The limitation with this scenario is that even though the contact has been deleted, the parent flow does not trigger because of the condition on the trigger. The parent flow will only trigger if the account name lookup column contains data.
But what if you remove the condition from the trigger?
Even if we removed the condition and deleted the contact record, the parent flow does trigger but it fails.
This is because the parameter value for the TargetID which is the GUID of the account record is missing in the trigger.
Is there a workaround to this limitation in order to refresh the previously associated account record?
So what is the underlying limitation with using cloud flows to refresh rollup fields? Well there’s functionality missing in the Dataverse connector as of when this WTF episode was published.
This missing jigsaw piece is the pre-image and context of the event. In other words the Dataverse trigger does not know what the previous value was for the account when updating the account name lookup field for the Contact or deleting the Contact. The trigger response only knows of the current value it was updated to. The pre-image and context functionality exists in the traditional SDK of Dynamics 365 and Dataverse but has not yet been exposed as a capability in the Dataverse connector.
Is it worth automatically refreshing rollup fields with cloud flows?
Now for the million dollar question – is it worth using flow to refresh a rollup field in near-time? If your requirement is for rollup fields to be refreshed on create, then yes, worth it ✔️
Otherwise until the pre-image and context is supported in the Dataverse connector, I don’t think it’s worth it ❌
Summary
I shared two methods with you in refreshing rollup fields.
Method 1 - using a single cloud flow
Method 2 - using Parent and Child flows to make the automation reusable
The following are the scenarios I went through with you for Method 1 and Method 2,
where only scenario number 1 was in my opinion an all round-success for refreshing the rollup field. Scenarios number 3, 4 and 5 were not yielding the behaviour I would have like since pre-image and context is not yet supported.
However when the product team does support it, then definitely Method 1 and Method 2 would work. Method 2 is the one that allows you to reuse the refresh rollup field automation by multiple parent flows.
I hope you learnt something new. Don’t forget to subscribe to my YouTube channel and till next time, Bye!