Wednesday, 19 February 2014

Dynamics CRM - Enabling/Disabling Fields using Javascript - Common pitfalls

One of the great things about CRM is what you can achieve with some JavaScript. A very common use of this is making decisions on what fields should be disabled on a form when driven by more complex business rules. But with this power we need to take care! There are a few gotchas you need to be mindful of when using JavaScript to enable/disable fields.
  1. Avoid invalid states by employing an onload script.
  2. Be mindful of breaking workflow development
  3. This is UI side scripting, so can be bypassed by directly hitting the SDK.
Let's build an example to show and fix these downfalls.

Note that I am still working in the world of Dynamics CRM 2011 so most screen shots and comments will relate primarily to that environment.


The Requirement

We have 2 new fields on the contact form that need some JavaScript to help them function correctly:

  • First is an Option Set called "Occupation" with the choices 
    • 1 - Sales Manager
    • 2 - Computer Programmer
    • 3 - Administrative
    • 4 - Other
  • Second field is a text box called "Other Occupation" that should only be enabled when they select "Other" from the option set
  • "Other Occupation" is a required field if they select "Other" from the option set


The Code

Firstly, let's customize the form and disable the field by default (hint: this causes our first bug):



Now let's create a new script to run off the on change event of the new optionset. Our JavaScript function should look like this:


function setOtherEnabled() {
    if (Xrm.Page.getAttribute("new_occupation").getValue() == 4) {
        Xrm.Page.getControl("new_otheroccupation").setDisabled(false);
        Xrm.Page.getAttribute("new_otheroccupation").setRequiredLevel("required");
    } else {
        Xrm.Page.getControl("new_otheroccupation").setDisabled(true);
        Xrm.Page.getAttribute("new_otheroccupation").setRequiredLevel("none");
    }
}


Testing

Once this has all been linked up to the on change event of our occupation option set we can give this a quick test. Changing to "Other" produces the correct result:


Looks good so far. Let's type in an occupation and save it. This looks fine, until we check how it has reloaded it:


So there's a problem. When the form reloads it disables this field by default, but hasn't recognised that the Occupation has been changed to "Other".


Tip 1


When using JavaScript to enable/disable fields on a form, dependent on other field values, always use a form onload event to initialise fields to their correct state.


The Code (V2)


function onLoad() {
    setOtherEnabled();
}


function setOtherEnabled() {
    if (Xrm.Page.getAttribute("new_occupation").getValue() == 4) {
        Xrm.Page.getControl("new_otheroccupation").setDisabled(false);
        Xrm.Page.getAttribute("new_otheroccupation").setRequiredLevel("required");
    } else {
        Xrm.Page.getControl("new_otheroccupation").setDisabled(true);
        Xrm.Page.getAttribute("new_otheroccupation").setRequiredLevel("none");
    }
}

Hook up that onLoad function to the form onload event. Now refresh the contact page and it's looking much better.


New Requirement!

As with all projects requirements will change and evolve with the business, so let's introduce something new. For the purpose of this example let's say people seem to type in HR and we wish to make sure it is entered as "Human Resources". Our developers are busy so we are going to write a workflow to update the Other Occupation while we wait on a plugin. In CRM 2013, this could be handled differently, but for now let's presume we're stuck in the dark ages of CRM 2011!

Create a new workflow to fire off update of a contact and set the Other Field... and this is where we hit our next Gotcha...



We cannot update the "Other" field because it has been disabled in the workflow editor. This is because we disabled it directly on the form by default.


Tip 2

Never disable fields directly using a form customisation if you want to access it via workflows. Use javascript onload events instead.


Fixing it up

Thankfully for us we already put in an onload event to fix the first bug (to handle the behaviour state of the new field), so this means we already have the JavaScript onload event firing for this. This means we don't need to disable the field by default on the form as the onload will do this for us. So all that is left to do to fix up the issue is undo the first customisation we performed as per this screenshot:




Wrapping up

The last point we need to be aware of is that because this is JavaScript the validation of it being a required field only happens at a UI level. In general this is fine, because this is consistent with the standard CRM field level requirements (you can bypass all required fields if you create records directly via the SDK). So generally I don't bother implementing any server side validation to catch these type of fields.

In summary, always be aware of the most important gotchas when using JavaScript to control fields in this manner:
  1. Use onload events to initialise field behaviour.
  2. Don't default field behaviour by making customisations directly on the form if you might need to work with the fields in workflows.

No comments:

Post a comment