How To Make Dialogs For Model-Driven Apps Using Custom Pages

This week the Custom Pages were released to public preview: here the official blog.

This is a huge step towards having only one app type; not having to decide which App type to choose. But it also means, that we finally get the low-code possibilities right inside the model-driven apps. Aaaand.. we don’t have to pay an additional license, because it’s not a new app, but only a page inside the model-driven app. Now we’ll be able to accomplish a lot of scenarios we were struggling before. One of them is how to make a Dialog in model-driven apps.

How to make a Custom Page

First of all, let’s make a model-driven app. The best way to start is from a Solution.

We’ll use the new maker-portal, using the We’ll make a model-driven app and edit it using the new maker experience:

There we create a new Page of type Custom:

There we can create a new page, or choose an existing:

Choosing “Add” will navigate us to the page designer, where we have a very similar experience with a Canvas Page designer.

We can also add an existing Custom Page to the App:

Editing a Custom Page

The process of editing a CustomPage can be started through the App designer (like above). An existing Custom Page can be also edited from the Solution, directly choosing the Page.

Since we are making a page for a model-driven app, we need to consider making it responsive, just like the rest of the app. That’s why I’ve used a vertical container, and inside it, four horizontal containers, for each control or button row.

The purpose for my dialog is to generate a task for an account, allowing me to choose some input data (like subject, priority or due date). This dialog is just an example of what we can do with Custom Pages. Later we can extend the example, and autogenerate tasks for all selected accounts from a list. Of course, there might be a lot of interesting requirements, including choosing records from some other tables or even combine with PCFs. Everything is possible now.

Important: In order to try out the App, the page must be published, and after that the app must also be published . These two steps need to be made after every change in the page.

How to open a Custom Page as a Dialog

Let’s suppose that we have the CustomPage done, and we want to open it from inside an Account Form. For that I’ll use the SDK Xrm.Navigation.NavigateTo functionality (for now I’ll use the console, but this can be executed from the form scripting or from a ribbon button)

Here is the code used:

   pageType: "custom", 
   name: "diana_dianamicsdialogpage_19356", 
   entityName: "account", 
}, {
   width: 700, 
   height: 400

There are two important parameters here:

  • “pageType”: “custom”. The navigateTo has a new pageType now. Before CustomPages we could use the pageType with the values: “entitylist”, “entityrecord”, “webresource”, “dashboard”. Now the docs include also the “custom” type.
  • name: “diana_dianamicsdialogpage_19356”. The name of the CustomPage can be found in the customizations:

Tipp: I wasn’t able to copy the name from there. In order to copy it, I’ve used the Solution Layer. There we can find the name and copy it

I could have used the same dialog by opening it on the side. I only need to pass the “position: 2” as navigationOptions, together with target and width. But for my very few fields, is not the best experience:

Implementing the action

When I want to open a dialog, I need to do something with the data. I am not aware of a way to pass the data from the dialog back to the opener function. So the generation of the task will take place directly inside the CustomPage. Using low-code.

Grabing the recordId

First we need to be able to read the recordId, the accountId where the dialog was opened. For that we go in App, OnStart and grab there the Param “recordId” and save it in a variable: RecordId.

I’ve struggled for a while to get the Lookup for the account. The RecordId variable was looking good, but the RecordItem was always null. Until, I’ve noticed that I need to remove the curly brackets before calling the GUID function. In case you know a better way, please let me know.

Set(RecordId, Substitute(Substitute(Param("recordId"), "{", ""), "}",""));
 LookUp(Accounts, Account = GUID(RecordId))

Actually the reason I need the account lookup, is because i must use a “Patch”, where the account will be used as a “Regarding”. If you know a way to make the “Patch” containing the Regarding directly using the RecordId, so without using the Lookup function, please, please let me know,

The buttons

For the “Cancel” button I only need to navigate back.

The “Generate” button need to make a “Patch”, in order to create the task.

Patch(Tasks, {Subject: InputControlSubject.Value, Regarding: RecordItem, 'Due Date': InputControlDatePicker.Value });
Notify("Task created");

For now I’ve only passed the subject, the due date and the regarding account. I show a notification (which unfortunately is shown only inside the dialog, which closes automatically, so we basically don’t see it), and then I close the dialog by using “Back()”.

In case the dialog closes, and you don’t see the task generated in your account timeline, you could try to use


instead of the “Back()” command. This will reopen the underlying record, so it forces it to do a full refresh.


I have on older blog where I has happy to find a workarround to transform form into dialogs. Now we can forget all that tricky ways. Finally, we have a way to design dialogs provided by the platform.

But using the CustomPages as dialogs is only the tip of the iceberg. The Converged App will offer so much flexibility. I’m really looking forward to apply the new possibilities. A game changer!

The Custom Pages docs have a lot more details: have a look here.

8 thoughts on “How To Make Dialogs For Model-Driven Apps Using Custom Pages

Add yours

  1. Does it allow to send back the information to parent page. In my last project, I used Widnow.sessionStorage object to store the info and pushing back to the parent page.

    1. Unfortunatelly until now there is no supported way to pass data back. One approach could be to execute all the code using low-code or PCFs inside the CustomPage. After that we can use “Back()” or one of the Navigation methods, which would refresh the opener window-context.
      There is also a workarround for the case where the CustomPage is saving some data somewhere. In that case we can read that data from the Dataverse, after the dialog was closed, and get that way a kind of response.

      In my opinion the sessionStorage approach is not really safe. One problem is that there could be more browser tabs opened, which shares the same sessionStorage, where the same CustomPage might be opened. So there must be a safe way to know which sessionStorage key was set for this instance of the CustomPage.
      Also, the PCF docs says not to rely on sessionStoarage. I use it for caching purposes, but if it’s not available, the application should still work, so I wouldn’t rely on it. Here the docs:
      I really hope Microsoft will provide in the future a way to pass the data back from the dialog.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Website Powered by

Up ↑

%d bloggers like this: