Transform Forms into Dialogs and more…

Xrm SDK methods for hiding the header and footer: welcome ๐Ÿ™‚

Yesterday I’ve seen the new SDK methods for hiding the header and footer areas on the form, and the first impression was: WOW! I just had the feeling that I’ve missed this feature since ever. So I’ve tried to remember where I’ve needed this in the past. The first that I’ve remembered was showing a form as a dialog. I’ve tried it out, and with this blog I want to share the results.

[Edit] In the meanwhile, I’ve created a new PCF to improve the buttons for this kind of dialogs. Read mode about Dialog Buttons in my next blog post.

The “Big Picture”: The reason for this sdk feature

There might be a lot of other use cases where the new methods are useful, but I’m pretty sure: this SDK methods were not introduced because of these use cases; they are just “side effects”. I suppose it is a part of a bigger change in the direction of converging the app types: model-driven and canvas apps. The first target could be the Custom Pages, where I suppose we’ll be able to integrate also forms. Having the header and footer would look unnatural. The public preview for Custom Pages is scheduled for December 2020, so I guess we’ll find out soon enough.

Who knows, maybe the combination of Forms-Without-Header and Custom-Pages might be the intermediate answer for the deprecation of ClientGlobalContext and parent.Xrm for WebResources that are not on the form. At least until everything will be migrated to PCFs. But that’s a little like “fortune telling”. Who knows what might come in the future.

Scenario

Let’s imagine that we need a dialog, where we ask a few questions before an action is made. There might be a lot of cases:

  • Ask for a reason, an amount and a comment before we deactivate a record
  • Ask about a few details before we generate some related records from a ribbon button
  • Maybe we don’t use business process flow for an entity, but we have some fields on the form that needs to be confirmed in a special case

I’m sure you have better examples for the need of the dialogs. The need was always there. The sdk “Xrm.Navigation” has only openAlertDialog, openConfirmDialog, but that’s not enough for grabbing some more input. There are some other ways to implement it: like making CanvasApps or making own HTMLWebResources. But there are some problems with them: like license issues, loading performance issues, or at least too much effort to implement it (in the case of HTMLWbeResources). So I’m trying to implement the Dialog with pure dynamics 365 customizing and a little JavaScript.

Set up

Since I need a form for my dialog, I have two possibilities: make a special form for an existing entity, or make a special entity used only for dialog(s) (in my case “orb_dialog”). I think both cases can be used; it depends if I already have the needed attributes on my entity. My Form-Dialog will never save the data. I just use the form for grabbing the input, before I start an action.

To open the form I’ll use Xrm.Navigation.navigateTo. This offers the possibility to open a form in a “modal window”.

The code can be found in my github repository (open.js for this one).

[Edit]: As Andrew Wolfe noticed, the Xrm.Navigation.navigateTo parameter is “createFromEntity” and not “createdFromEntity”.

The result

The Xrm.Navigation.navigateTo can be called from a ribbon button or some other form scripting. This will open the from as a dialog. Inside this form I have some JavaScript for hiding the header an footer, and some script to prevent the form to save the data. I use it only as a container for the inputs, until I grab the data.

The customizing

In my case I had a custom entity which I use only for the dialog: orb_dialog. But as I said, an existing entity could be used too: I just need a dedicated form.

I’ve integrated also a PCF for the the optionset field (my ColorfulOptionset PCF which you can download from pcf-gallery). The possibilities are huge, since I can use every possible form customization.

On click on a button, I want to grab the data introduced, and make an action. For the button I’ve took a PCF from the pcf-gallery: Action Button by Tanguy Touzard. This offers me the possibility to have a PCF, but the script for the action is still registered using form scripting, so I don’t have trouble with PCF restrictions.

[Edit]: In the meanwhile I’ve made a new PCF Control for the button which is translatable, allows the definition of more buttons, and has a few more features. Read more about Dialog Buttons in my next blog post

For the action I’ve took a custom attribute “orb_action” of type text. It’s a dummy attribute, I won’t save it. If the button is hit, the PCF changes it’s value to the one customized for the label (in my case “Evaluate”); so I can register an “OnChanged” to orb_action attribute and start the action.

Form Scripting for the Dialog-Form

The javascript part for hiding the header and footer areas is very simple:

[Edit]: The initial idea was to stop the saving, but grab the values. The edited version is much simpler: setting for all attributes the submitMode on “never”. That way the inputs are not relevant for the form, but can grab the input for the Dialog-Action.

I registered the “onChange” for the action attribute (PCF):

In order to have the attribute-list flexible, I have an array with my needed attributes (I don’t take all of them, since there are some more attributes there, which are not visible anymore). My event handler looks like this:

In the “action” event handler “myAction” I do the following:

  • grab all the relevant values
  • I start the action (in my case the openAlertDialog stands in place for a complex action (it’s enough that it’s a promise)
  • I close the form

Passing parameters

To pass parameters to the dialog, we can use the data parameter for Xrm.Navigation.navigateTo. For instance to pass a lookup we need to pass <lookupAttribute>, <lookupAttribute>name, <lookupAttribute>type (see here the docs):

Xrm.Navigation.navigateTo({
    pageType: "entityrecord", 
    entityName: "orb_dialog", 
    entityId: "83BD09D6-930D-EB11-A813-000D3A23CB53", 
    createFromEntity: { entityType: "orb_pcftester", id: Xrm.Page.data.entity.getId(), name: "dummy" }, 
    data: {
        orb_pcftester : Xrm.Page.data.entity.getId(), 
        orb_pcftestername: "dummy", 
        orb_pcgftestwertype: "orb_pcftester"
     },
     formId: "830fb574-f340-40e6-ad64-93b2033a1c6e"
}, {
    target: 2, 
    width: 600, height: 350 ,
    position: 1
}).then(console.log, console.error)
Now the lookup is set when the dialog is opened

A bigger problem is passing parameters back to the calling function. Unfortunately the Xrm.Navigation.navigateTo won’t allow to pass parameters back. With one exception: if the dialog-form is opened in create mode: then we’ll get the id of the dialog-record when the promise is resolved. BUT, that will create a lot of trash-records in the dataverse, so I wouldn’t recommend it.
I think the best option is the write the code for processing the dialog right inside the dialog-form, and provide the needed parameters while opening the form.

Form scripting – “X” Button issue

[Edit]: In the initial idea, the “X” button made some issues, because the dialog “Unsaved changes” was showing. This is not relevant anymore, since all the attributes are set on “never submit”, and this “Unsaved changes” doesn’t appear anymore. This part is not relevant anymore, that’s why I’ve set the text to gray.

We cannot control if the “X” button is shown or how the form behaves when it’s clicked. If there is already data introduced in the dialog-form, a confirmation dialog is automatically shown. If the user chooses “Save and continue”, the OnSave is automatically called.

So I had to go through that kind of form scripting we’ve always done, by registering to “onSave” and there stop the saving until we’ve made the async action. ( Unfortunately the last part of the sdk where we cannot work with promises. ๐Ÿ˜ฆ )

That’s actually the tricky part of the implementation, even if it’s not much code:

The “dialog name” issue

[Edit]: In the initial idea, the name of the dialog couldn’t be changed, because there were issues with the autosave. The old text is set to gray.

What you see as “New Dialog” on the top of the dialog, is actually the form name. Since I open in “create” mode I get “New”, and since my entity’s name is “Dialog”, I get “New Dialog”.

If you want to set the name of the dialog to something else, just make one record in the “Dialog entity”, and name it exactly how the dialog should be named. In my case “Confirmation”. The difference is that you need to specify the entityId when opening the form:

And now we have a nice title:

This is not possible if you use a “real” entity for the Dialog (in my case it’s an entity only for the dialog). Also this means that you need to transport this entity-data together with the customization. Is it worth to implement it like this? It depends if the customer is ok with “New Dialog” as a title, or not.

I don’t have a good solution for this. I’ve tried to open the form in “Update Mode”. For that I took a record in my “Dialog” Entity, and named it “Confirmation”.

Now the title it’s looking good, but then I had issues with my “onSave” script: the onSave is called before the Confirmation “Unsaved Changes” are triggered, and then I would need another confirmations, while the standard is coming somehow on top. So I’ll go for now with opening the dialog-form in Create mode.

Have a look to the complete code in my github repository.

Dialog as a Wizard?

I think that could work too. For instance we can make more tabs on the form. We use setTabNavigatorVisible(false), which makes the tabs hidden. But using code we can still navigate to the other tabs using “formContext.ui.tabs.get(xxx).setFocus()”. So maybe we need a PCF-Upgrade for “Action Buttons” (or another one, implementing a set of buttons for Wizard-Navigation), and a little more Form-Scripting, but I don’t see why this wouldn’t work.

Final thoughts

I’m sure this solution can get more generic and can be better implemented; it’s more like an idea in the beginning. I’m excited about this idea, since it offers all the customizing possibilities, allows us to use even PCFs and form scripting, BusinesRules and we get all the checks on top.


I’m also curious what use cases of this new sdk feature will come in the future.

15 thoughts on “Transform Forms into Dialogs and more…

Add yours

  1. Hi Diana. Nicely written Blog post. Itยดs clearly structured and easy to follow along, even for us “Citizen Developers” :). This requirement to use dialogues indeed is very common. Now it seems like we have an efficient way to implemnt such a feature. Thanks for sharing!

  2. Fantastic! I don’t remember how many times I have told clients that the JS dialogs is top notch of what you can get ๐Ÿ˜‰
    And very well written as well.

  3. Thanks for this article I’m busy using this on a project now, I’m using it to create a new record with a lookup to the current one using the dialog and it wasn’t working. I think you have createdFromEntity where you mean createFromEntity – took me a while to spot

  4. Hi Diana,
    Thank you for this very nice blog.
    We were implementing your solution for a specific business need: launching a dialog on a grid or a view.

    However, we’re having a problem with passing parameters: on the dialog form, we have a lookup field and we need to grab the selected record and pass it back to where the dialog was opened.
    Do you have a way to do that ?

    The callback will be null in our case because we’re using a create form but not saving anything.

    Another option in our scenario would be to pass the selected records on the grid or the view to the dialog form and then code the action on the validation. But we haven’t found a solution to pass this kind of object to the dialog form.

    Any help would be appreciated.

    Thank you,
    Marc

    1. Hi Marc,
      Thank you for the question, I’ve edited the blog adding the “Passing parameters” chapter. Please have a look above.
      Basically you can pass the parameters to Xrm.Navigation.navigateTo using the “data” property. I would recommend processing the data right inside the dialog-form, since there is no good way to pass the grabbed data back to the opener function.
      Hope this helps!

      Kind regards,
      Diana

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

Website Powered by WordPress.com.

Up ↑

%d bloggers like this: