Working with Dynamics CRM 2013 Composite Fields/Fly-out Menu

Paul Nieuwelaar, 22 October 2013

Dynamics CRM 2013 introduces composite fields, which basically combines multiple fields into a single field on a form. This is currently used on ‘Name’ fields to combine first name, middle name, and last name into one ‘Name’ field. It is also used on most address blocks in CRM by combining all the address fields into a single composite field.

As you can see above, we have a single ‘Address 1’ field, which when clicked opens a fly-out menu with our 7 address fields. We can then change the individual values and click ‘Done’, or simply click off the fly-out menu to commit the changes.

The 7 address fields are then combined and formatted nicely into the ‘Address 1’ composite field, so that you can easily see the whole address in 1 field, rather than having to look across 7 different fields. This field can then be added into views and reports, or even exported to excel.

This new composite control is used for most of the main entity address blocks in CRM; including Account, Contact, Lead, Competitor, Quote, Order, and Invoice. It is currently not used on User, Business Unit, and Site. It’s also used on the Name/Full Name fields for Lead and Contact (but not User). Unlike the addresses, the Name composite fields use the existing Name/Full Name field, rather than a new field.

As you can see with the Name field, it uses the Middle Name field in the fly-out menu, but this is not added to the actual ‘Name’. If you wanted to see the person’s middle name, you would need to click into the Name field to open the fly-out menu.

The big question is how customizable is it?

Unfortunately we can’t create our own composite controls. Hopefully this is made possible in a future release, as that would allow for consistency when adding custom entities with address fields etc.

As for customizing the existing composite controls, we also cannot add, remove, or modify fields in the fly-out menus through the UI. This means that for us New Zealanders where we don’t use the ‘State’ address field, we cannot easily remove that from addresses now, or even relabel the fields. Hopefully this is also made editable in the future through the UI.

JAVASCRIPT
Next I wanted to explore how the composite controls hold up against JavaScript. Mainly I will be testing the functions commonly used on address fields and name fields, to make sure they can still be used with the composite fields.

1. JavaScript OnChange events on fields in the fly-out menu

Since each individual field inside the fly-out menu is not actually on the form by default, we can’t directly add an event handler to the onchange event of one of these fields. We can however add onchange events to the composite field. In the case of ‘Middle Name’ though, this will not work, as entering a middle name does not update the composite ‘Name’, and so the onchange does not fire.

By adding the event handler to the composite field, it also means the event will fire on any change, and not just when a specific field in the fly-out menu changes.

A better way to handle onchange events on individual fields is to add a hidden section to your form, and add each of the individual address fields into this section. You can then add JavaScript event handlers to the individual fields which will also be applied to the fields in the composite fly-out menu.

As soon as you change the field value in the fly-out, the onchange will fire; even before completing the other fields in the fly-out. You can see here I have a simple function to alert the Country/Region when it changes.

Note: Using .addOnChange() JavaScript does not work. There is no error, but the event is also not fired when changing the value inside the fly-out menu.

2. Getting the value of a field inside the fly-out menu using JavaScript

Now I wanted to try getting the value of a field inside the fly-out menu, where the field is not actually on the form otherwise. Here I am simply alerting the Middle Name of a contact onload:

alert(Xrm.Page.getAttribute("middlename").getValue());

Booya! We can get the field value even though it’s technically not on the form.

3. Setting the value of a field inside the fly-out menu using JavaScript

We can easily ‘get’ the field value, but can we easily ‘set’ the field value? I’ll try a simple setValue() on the Country field to set it to New Zealand by default.

Xrm.Page.getAttribute("address1_country").setValue("New Zealand");

Hmm… not quite right. As you can see above, the composite field is still U.S. but when we click into the field to see the fly-out menu, the country is New Zealand. You can also see in the corner that there are unsaved changes, so CRM has recognised that something has changed.

The composite field won’t be updated until you open the fly-out menu, and then close it again. You can also perform a save (or wait until the auto-save kicks in) and then the composite field will be updated.

We also cannot manually set the value of the composite field (in a supported manor) using JavaScript.

4. Hiding fields in the fly-out menu using JavaScript

Next I wanted to try something a little more complex, hiding one of the fields in the fly-out menu:

Xrm.Page.getControl("middlename").setVisible(false);

No luck here unfortunately. While ‘Xrm.Page.getAttribute’ seems to give us the correct attribute inside the fly-out menu, it looks like ‘Xrm.Page.getControl’ does not give us the control.

Before I give up, I wanted to try some “unsupported” JavaScript as well to see if we can hide it that way:

document.getElementById("fullname_compositionLinkControl_middlename_d").parentElement.style.display = "none";

Hooray! We can hide fields using unsupported JavaScript. However remember that being unsupported, this could break at any time with a future update (or more likely they add support for it).

The element name you need to get includes the composite field name, and the name of the field inside the fly-out menu you’re hiding: “<composite-field-name>_compositionLinkControl_<fly-out-field-name>_d”. For example, to hide the ‘State’ field in the Address 1 block, we would use “address1_composite_compositionLinkControl_address1_stateorprovince_d”.

5. Change Requirement level of fields in fly-out menu using JavaScript

This one is pretty important where we need to conditionally make fields required.

Xrm.Page.getAttribute("firstname").setRequiredLevel("required");

Bingo! First Name is now required.

6. Change the label of fields in the fly-out menu using Javascript

The First Name, Middle Name, and Last Name labels are taken directly off the field name, so you cannot change these on a per-form basis. However, to change the label for all forms, simply change the actual field display name, and the label inside the composite control will be updated.

Here I have customized the Last Name field display name to be ‘Surname’.

The address fields however cannot be changed through the UI. These do not appear to use the field display names, and instead appear to be hard-coded into the composite control. We often localise the address fields for New Zealand addressing, so I didn’t want to give up on this one that easy.

The supported control.setLabel() does not work as we cannot get the control of the field inside the fly-out menu. The last resort was to try “unsupported” JavaScript.

document.getElementById("address1_composite_compositionLinkControl_address1_line1_c").firstChild.firstChild.innerHTML = "Street Address";

Success! The label has been changed inside the fly-out menu. Just like with hiding the fields, we need to specify the address composite field name, as well as the name of the field we’re changing. You can then specify the new label for the field. This approach is unsupported, so use it at your own risk.

BUSINESS RULES
Now we've seen how JavaScript works with fly-out menu, I wanted to see how we can use Business Rules on fields in the fly-out menu. I will put to test all 5 ‘actions’ we can perform with Business Rules, and see if the results are any different to JavaScript.

1. Show error message using Business Rules

We can add some validation to a field inside the fly-out menu, the red ‘X’ will appear next to the composite field. If we display multiple error messages, for example on Street 1 and 2, only 1 ‘X’ will appear beside the composite field.

2. Set field value using Business Rules

Just like with the JavaScript, this sets the value inside the fly-out menu, but doesn’t update the composite field until you click in and out of the field, or save the form. Note: we can also ‘get’ the value of fields in the fly-out menu from Business Rules when setting another field on the form.

3. Set business required using Business Rules

This one works as expected with no issues, same as the JavaScript.

4. Set visibility using Business Rules

We could do this using JavaScript, but it was using an unsupported method. I’m happy to see that this does work with Business Rules. You can see here I have a business rule with no condition (so it always fires) with an action that hides the Address 1: State/Province field. The result is that the field is completely hidden from the fly-out menu.

This works better than the JavaScript approach, and is supported too.

5. Lock or unlock field using Business Rules

This one was not possible using JavaScript, because we couldn’t access the ‘control’. Fortunately we can do this using Business Rules. You can see below the Street 2 field has been locked (disabled) inside the fly-out menu.

In summary, composite controls are pretty cool, and save us a lot of room on the form, especially with the addresses. It would be great if in future using just the UI we could do some of these basic customizations which are so often required in customized solutions, without the need of unsupported JavaScript. It would also be nice to have a bit more flexibility with JavaScript so that we can do conditional showing/hiding or enabling/disabling of fields inside the fly-out menus.