Thursday, May 18, 2017

Showing and hiding sections on a form + quirks

Showing and hiding sections on a form is not possible to do in a fully supported way without hiding all components of the section.
This can be quite arduous, and in addition someone might have created a business rule that messes that up for you and all of a sudden, it's visible anyway.

To help with that there's a great little function hidden in the client side library that you could use
Xrm.Page.ui.tabs. get(delegate: MatchingDelegate<T>): T[];
This little bit lets you query for a tab using a filter in form of a function. This will let you specify criteria like section content and other properties/attributes.
This means you loop through all tabs on the form and filter by the criteria specified. I’m doing the following (please notice that I’m writing in typescript):
var parentTab = parent.Xrm.Page.ui.tabs.get(t => {
    return t.sections.get("MyUniqueSectionName") !== null
var mySection = parentTab[0].sections.get("MyUniqueSectionName");
For the first part, I’m creating a delegate function of t, where t is the current tab being iterated over.
Inside the delegate there’s a short one-liner which returns true if there is a section in the tab with the unique name. This will generate an array of tabs as a result set. I made sure that I used a unique name for my section so I will only get one tab in return.
Next I collect the section from the result set, and finally set the visibility to false.
Putting this into a reusable function with two parameters, I can now utilize it as follows:
setSectionVisibility("MyFirstUniqueSectionName", false);
setSectionVisibility("MySecondUniqueSectionName", true);
Now I can reuse the function and trigger it on field changes or form load to make sure I only show the sections applicable for a given scenario.


I found one quirk with this which was kind of annoying, but luckily the fix isn’t particularly hard. If you have a business rule which shows and hides fields in a section, and that section is hidden at the same time (for example if you trigger on change of a field, and both the business rule and this javascript snippet triggers on the same change), then the following quirk happens.
The section stays visible, but if you write out console.log(mySection.getVisible()) it will say “false”. I assumed there was some race condition going on, because if I hid a field with a business rule at the same time as I hid the section with this javascript, then the section stayed visible but the field got hidden. I did some testing and found out that if you put it inside a setTimeout() then it works like a charm. What I ended up doing was this:
setTimeout(f => {
    setSectionVisibility("MyFirstUniqueSectionName", false);
    setSectionVisibility("MySecondUniqueSectionName", true);
}, 10);

Even though the timeout is only 10 milliseconds that’s still enough to prevent the race condition, and everything works brilliantly.

Another thing I found is that the tab has another, undocumented function: Xrm.Page.ui.tabs. getByFilter(delegate: MatchingDelegate<T>): T[];

This does the same thing as get(…), but has a longer, more explicit function name. Seeing that this is undocumented I would stay away from it as long as both do the same thing (using Daryl Labar’s DefinitelyTyped definitions for Xrm in Typescript will only show the documented function).

I have been notified that the xrm definitions of DefinitelyTyped is an effort made by the following:
David Berry
Matt Ngan
Markus Mauch
Daryl LaBar
Tully H

1 comment:

  1. I would not consider the DefinitelyTyped definitions for XRM mine. Dave Berry was the original instigator, but it truly is a community effort. Currently these are the individuals that are listed as maintaining it: David Berry ,
    Matt Ngan ,
    Markus Mauch ,
    Daryl LaBar ,
    Tully H