This post is part of a series of posts. Please use the links below to navigate through the related posts:
- Macro Templates Introduction
- Deployment
- Dataverse Tables
- Custom Page Dialog
- Power Automate Flow
- Javascripts
- Template File
- Final Notes
- Git Sources
Custom pages are great – they are easy to develop, they can do what a canvas application can do, and they work within the model-driven application.
We can also use custom pages with Xrm.Navigation.navigateTo to create all sorts of popup dialogs:
In the Macro Templates solution, there is “a “Template Selector” custom page which provides the functionality required to:
- Choose a template from the list
- Call a Power Automate flow and display a progress indicator till the flow is finished
Here is how it looks like in the application:
So what does that page do?
- The list of templates to choose from comes directly from the “Document Templates” table
- Once a user picks a template and clicks “Next” button, this pages displays a spinning wheel and calls a Power Automate flow right away. We’ll look at the flow later, but, in short, that flow is responsible for exporting data from Dataverse to an excel spreadsheet which, in turn, gets stored in Sharepoint. The flow also provides a bit of additional plumbing by accepting actionid parameters which comes from the javascript calling the custom page, and the flow is using that action id to create a new record which the javascript can read once everything comes back to it. That way, the javascript knows which file to download (by using actionid to find a record in the Template Download dataverse table and looking at the fields there)
This custom page is pretty simple, there are just a few gotchas there.
First of all, how do we pass additional parameters to a Custom Page?
Xrm.Navigation.navigateTo allows us to pass for parameters: pageType, name, entityName, recordId. All the other parameters added to the pageInput are simply ignored. Luckily, while the first two parameters have to have very specific values, the other two (or, at least, the entityName one) seem to allow just about any string to be passed through them. So, then, why not to pass a json?
And use app onstart in the custom page to parse that json:
That way, I can pass actionid among other things, and I can also pass localized labels for the user’s current language right to the custom page (there are other ways to do translations, but why bother doing anything else on the custom page side if I already have everything I need in the javascript).
And, then, how do we pass custom page “execution results” back to the javascript?
I’ve already written about it in the previous posts, but, basically, this solution is using a custom table for this (“Template Downloads” table). A page (actually a flow that is called from the page), will create a record in that table, will set the fields, will fill in “actionid” parameter(remember it comes from javascript, and it’s, basically, a timestamp), and, then, the custom page will be closed.
The javascript will look for that record using actionid to filter the results, and, if there is a matching record in the table, the javascript will use it to download a file:
There are a couple of other things to mention:
- navigateTo rarely “fails”. For example, if you forget to add your custom page to the MDA application, navigateTo will finish successfully right away, there will be no errors, but it will not open a custom page either
- There seem to be no way to block “X” button which closes the custom page dialog. However, with the above, if there is no record in the “Template Downloads” table, the script does nothing in such case