Build dialogs using model-driven pages to run flows all with low-code

Low-code is all the rush these days. It makes for more maintainable solutions that are built faster, specially when it comes to extending existing platforms like Power Platforms / Dynamics. It makes our work more decoupled from that of Microsoft’s and we can each focus on building better solutions without treading on each other’s toes. 😊

One of the main extension points in Power Platform is adding custom buttons to the Command bar. If you are not fully familiar with command bar, be sure to read the following article in the official docs to know what it is and where it is before reading further.

Command designer overview – Power Apps | Microsoft Docs

The previous experience was called Ribbon which is still around. If you would like to know more about this evolution, please read the following page from the official docs.

Command bar or ribbon presentation (model-driven apps) – Power Apps | Microsoft Docs

What are we building?

  • Reusable JavaScript library to open custom pages as dialog boxes
  • Custom button in command bar
  • Custom page in model-driven app to act as a dialog box
  • A cloud flow

In case you are wondering if this is a good practice to display custom pages in dialog boxes, this whole thing is recommended by Microsoft, but the only caveat right now is that Microsoft has not (yet?) provided a low-code solution to open custom pages. Instead, they have given us a list of JavaScript samples that can be used as starting points. I specially recommend you read the first article to have a good idea of where we are headed.

A cloud flow that can be triggered by apps

First things first, right? If we are building a dialog box to run cloud flows, we would first need a cloud flow. Anything would do, just remember it should be a flow that can be triggered by Power Apps and I strongly recommend to respond back with the result in your flow.

You’ll notice in the following screenshot that I have a flow that uses PowerApps (V2) as trigger and at the end it is returning two parameters as a result to any app that calls the flow.

Adding a Respond to a Power App or Flow at the end will let the caller (app or flow) to know if your flow has succeeded or not and the caller will have a chance to react accordingly.

A custom page in your model-driven app

Next step is to build a custom page that can be used as a dialog box. The goal of this custom page (which is a kind od Canvas app with some more power from model-driven apps by the way) is to help end-user run a flow (or several flows) and wait for them to complete while displaying a spinner and once the flow complete let the user know if something went wrong or simply disappear and refresh the data in the form.

To add a custom page to your model-driven app, you need to open the app in the new modern editor and click on the New Page button.

I suggest you build your custom page the responsive way, so you can display it in any kind of dialog no matter what size. To make a responsive page, I take the following approach.

As you can see on the image, I have one screen that contains a vertical container, an image called BusySpinner, a rectangle that fills the entire page to hide the content when the flow is ongoing.

In the VerticalContainer, I have two horizontal containers, the first one contains the only input parameter (language) I need to ask to user and the last one contains the OkButton. In your case you might need several horizontal containers. One per each parameter.

The visual layout of the page is similar to the following diagram. If it’s not clear enough, let me know in the comments and I will write all the properties you might need in a table here.

You will two variables to store the state of the page, IsBusy and IsValid.

  • IsBusy – this variable will have the value true when the cloud flow is executing and false when not.
  • IsValid – this variable will be false by default and will be true when all the required parameters are given by the end user and they are valid.

In your app’s OnStart you need the following commands to initialize the variables. I use this event to also initialize a simple collection I will use to fill a combo-box for my language parameter.

Set(IsValid, Not(IsBlank(Param("recordId"))));
Set(IsBusy, false);
If(Not(IsValid), Notify("Opportunity is not selected!"));
ClearCollect(LanguageCodes, "EN", "FR", "DE", "PT");

Next, you’ll need to add the cloud flow to your page, once you do that, you can trigger it in the OnSelect event of the OkButton.

Set(IsBusy, true);
Set(FlowResult,'Generatemandatedocument'.Run(Param("recordId"), LanguageOptions.Selected.Value));
If(FlowResult.succeeded, 
    Notify(FlowResult.message, NotificationType.Success);Back(), 
    Notify(FlowResult.message, NotificationType.Error));
Set(IsBusy, false);

As you have noticed in the above code, I’m setting the IsBusy variable to true then I start the flow, while putting its result in a variable called FlowResult, this allows me to check the result of the flow in the line that follows. If the result is successful, I simply close the page (dialog), otherwise I’ll inform the user. At the end I set IsBusy to false.

To display the spinner and fade the content behind, when the flow is ongoing, you simply need to put the IsBusy in the Visible property of both BusySpinner and BusyOverlay.

You can also use the following expression in the DisplayMode property of the OkButton. This will disable the button when the flow is ongoing or when the input parameters are not valid.

If(IsValid And Not(IsBusy), DisplayMode.Edit, DisplayMode.Disabled)

Reusable JavaScript library to show custom pages in dialogs

Save the following script in a .js file (e.g. dialogs.js) and then open your solution in https://make.powerapps.com, and click on New, from the drop-down menu, open More and click on Web resource.

/* This function uses Navigation API to display a centered dialog. */
/* Simple parameters are used instead of object to make the function compatible with command bar parameters. */
function displayDialog(rowId, tableName, pageName, title, contentWidth, contentHeight, primaryControl) {
  const parseSize = (str, defaultStr) => (str || defaultStr || "500px").match(/([\d\.]*)(.*)/).splice(1,2);
  let [w, wUnit] = parseSize(contentWidth);
  let [h, hUnit] = parseSize(contentHeight);
    var pageInput = {
      pageType: "custom",
      name: pageName,
      entityName: tableName,
      recordId: rowId.replace(/[{}]/g, "")
    };
    var navigationOptions = {
      target: 2, 
      position: 1,
      width: {value: parseFloat(w), unit: wUnit},
      height: {value: parseFloat(h), unit: hUnit},
      title: title
    };
    Xrm.Navigation.navigateTo(pageInput, navigationOptions)
      .then(
        function () {
            if (primaryControl.getFormContext) { primaryControl.getFormContext().data.refresh(); }
            else {primaryControl.data.refresh();}
        }
      ).catch(
        function (error) {
          /* TODO: Add exception handling here. */
        }
      );
}
https://gist.github.com/rezanid/33d22ae5381d1d159737a9645d7be098.js

The above code is based on the Centered Dialog sample of Microsoft. I have only made a bit more production ready.

  • The whole script is a function that can be easily called from the new Command bar designer (still in preview).
  • Width and height have default values to be used in case no value is given by the custom button.
  • Curly braces are removed from rowId to make it Power App friendly.
  • When the dialog box closes, the content is refreshed.

Pay attention to lines 23 and 24 and see how I’m getting to the formContext object. It is done that way so you can use the same script from any flavor of command bar.

I recommend you improve the script to cover for some edge cases and more importantly add exception handling to notify the end-user properly if “something went wrong“. ☠

Adding a custom button to command bar

The new command bar editor can be found in the modern app editor (which is in preview at the time of this writing). You need to select an app in your solution and click on the three dots to open it context menu and select Edit in preview item. Just like the following screenshot.

Once in the new App editor, scroll down to the table where you its command bar to receive this fancy new button. In the following screenshot, you’ll notice I’m editing the command bar of Opportunity table.

Power Platform will ask you which command bar you are interested in. I am going to choose Main form, but in case you are wondering what are these options, you need to read the first link I have shared in the beginning of my post 😉.

Once in the command bar editor, add a new button with the following properties.

PropertyValue
LabelRun my flow (can be anything you want).
ActionRun JavaScript (in future I hope we will be able to use PowerFx instead).
LibraryThe name you gave to your web resource. I used fancy_dialogs for example.
NOTE!
If you can’t find your library in the list you will need to click on the pen icon just besides the drop-down menu.
Function namedisplayDialog
Parameter 1FirstPrimaryItemId
Parameter 2String | opporunity (this should be the logical name of your table)
Parameter 3String | fancy_flowlauncher (this should be the name of your custom page)
Parameter 4String | Run flow (this will be the title of your dialog)
Parameter 5String | 500px
Parameter 6String | 500px
Parameter 7PrimaryControl

If you have followed all the steps correctly, the end result should be similar to the following.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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

This site uses Akismet to reduce spam. Learn how your comment data is processed.