One of the things I like best about the Dynamics CRM 2011 form object model is that it exposes the requiredlevel attribute for form fields, so you can dynamically set fields as required or not in response to user actions. This is great if you have different types of a single entity and business rules dictate that you must capture different data values for each type. For example, let's say you use the out-of-the-box Contact entity to represent two kinds of customers, small and large. For the small customers, your agents need to always fill in a customer loyalty code field, but for the large customers this field will never be populated. In the absence of a way to dynamically set the required level, you have two choices:
- Make the field required at the Contact entity level and train your agents to type in something like "not applicable" or "N/A" for large customers. This, of course, fills up your database with garbage values.
- Make the field optional, but train your agents to always populate it for small customers. This approach is even worse. While you can report on agent compliance retrospectively, you will almost assuredly end up with incomplete data for some records.
In this post, I will show how to use JavaScript to set the requiredlevel attribute of a field based on two separate conditions:
- The value of another field on the form
- The value of a field on a related entity (think a Contact's parent Account record)
Same-entity dynamic requiredlevel condition
The following method handles a silly scenario in which we need to check if a Contact's middlename field is populated, and if so, set the telephone1 field requiredlevel to required. If not, the requiredlevel of telephone1 will be set to none.
function SetRequiredSameEntity() {
var middlename = Xrm.Page.getAttribute("middlename").getValue(); //get the middlename value
if(middlename!=null)
{
Xrm.Page.getAttribute("telephone1").setRequiredLevel("required"); //set required
}
else
{
Xrm.Page.getAttribute("telephone1").setRequiredLevel("none"); //set none
}
}
To enable this functionality, do the following:
- Create a new Jscript web resource that contains the SetRequredSameEntity method. I call mine, somewhat creatively I think, firstlibrary (new_firstlibrary).
- Open the contact form designer.
- Open the form properties.
- Add the firstlibrary library to the form.
- Add the SetRequiredSameEntity method to be called as part of the form OnLoad event. This is required so that the field is set to required if it already has a middlename populated when it loads. Make sure you enable the method, and you can, optionally, set dependencies so that the fields this method uses will not be removable from the form.
- Close the form properties.
- Double-click on the middlename field to open its property window. Go to the events tab and add the SetRequiredSameEntity method to be called as part of the field OnChange event just like in step 5.
- Close the field properties.
- Save your form changes and publish your customizations.
- Open an existing contact record or create a new one to see the changes in action.
Related-entity dynamic requiredlevel condition
The following code handles a scenario in which telephone1 should be required for Contacts linked to a parent Account with an accountnumber value of 1234. Otherwise, telephone1 is not required. Unlike previously where the data was already available to us from the current form, in this method we will need to execute an OData query to retrieve the accountnumber value for evaluation.
function SetRequiredFromParentAccount() {
//set the path to the odata rest service
//this can be hardcoded using the Organization Rest Service URL under Customizations->Developer Resources
var odataPath = "https://" + window.location.host + "/XRMServices/2011/OrganizationData.svc";
//default telephone1 requiredlevel to "none"
Xrm.Page.getAttribute("telephone1").setRequiredLevel("none");
//get the parent account lookup
var parentaccount = Xrm.Page.getAttribute("parentcustomerid").getValue();
//if it's not null
if(parentaccount != null)
{
//extract the id
var parentaccountid = parentaccount[0].id;
//set up the odata query
var retrieveReq = new XMLHttpRequest();
var odataQuery = odataPath + "/AccountSet?$select=AccountNumber&$filter=AccountId eq guid'" + parentaccountid + "'";
retrieveReq.open("GET", odataQuery, false);
//make sure we get json back
retrieveReq.setRequestHeader("Accept", "application/json");
retrieveReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
//request/response will execute asynchronously, so we need a callback function
retrieveReq.onreadystatechange = function () { SetRequired(this); };
//send the request
retrieveReq.send();
}
}
//callback function to parse the response and react accordingly
function SetRequired(retrieveReq) {
//4 means a complete response
if (retrieveReq.readyState == 4) {
//parse response to json
var retrieved = this.parent.JSON.parse(retrieveReq.responseText).d;
//get the accountnumber value - CASE MATTERS!
accountnumber = retrieved.results[0].AccountNumber;
//if the accountnumber is 1234
if(accountnumber=="1234")
{
//set the required level
Xrm.Page.getAttribute("telephone1").setRequiredLevel("required");
}
};
}
In this scenario we use two methods instead of one because the OData retrieve executes asynchronously, and we need a callback function to process the results whenever they come back. Beyond making sure you use the correct casing in your OData query and where you get the accountnumber out of the returned JSON object, it's basically standard JavaScript like before.
To enable this functionality, do the following:
- Set the value of the odataPath variable to your Organization Rest Service URL under Customizations->Developer Resources.
- Add these new methods to your script library.
- Open the contact form designer.
- Open the form properties.
- Add the firstlibrary library to the form if it's not already there from the previous example.
- Remove the SetRequiredSameEntity method to be called as part of the form OnLoad event, if it's already there. Add the SetRequiredFromParentAccount method to the form OnLoad event.
- Close the form properties.
- Double-click on the middlename field to open its property window. Go to the events tab and remove the SetRequiredSameEntity method if it's already there. Add the SetRequiredFromParentAccount just like before.
- Close the field properties.
- Save your form changes and publish your customizations.
- Open an existing contact record or create a new one to see the changes in action.
Here is the code for the complete library: new_firstlibrary.js (2.02 kb)