Dependent Option Sets (Continued)

Diggin’ On James Brown…

Last month I posted a sample solution which demonstrated how to use some of the capabilities of CRM 2011 (such as JScript libraries, global option sets and the new client-side object model) to develop re-usable, dependent option sets (pick-lists). In that example I had two pick-lists on a form, one containing a list of countries and the other a list of regions (EMEA, APAC, Americas etc.). Whenever a country was selected from the first pick-list, a JScript function would display the correct region in the second pick-list.

But what if I wanted the reverse scenario, where I select a region from one pick-list, and only those countries from that region are visible in the second pick-list?

CRM 2011 Dependent Option Set Part II Example

Like before, the code to achieve the simple case is fairly easy to write, but what if I wanted to build a JScript library that would allow me to re-use my logic, without having to hard-code specific field names? In addition, CRM 2011 introduces the ability for multiple copies of the same field on a single form, so how would my code cope with deal with a field which had multiple controls?

Luckily, CRM 2011 introduces a much richer client programming model than previous versions of CRM, which makes this straightforward. I have two main JScript functions, formOnLoad() and attributeOnChange(), which do some simple error handling before calling updateDependentOptionSet(), which does most of the heavy lifting.

   1: formOnLoad(context, attributeName, dependentAttributeName) {
   3:     if ((this.isValidContext(context)) && (this.isValidOptionSet(attributeName)) && (this.isValidOptionSet(dependentAttributeName))) {
   4:         this.updateDependentOptionSet(attributeName, dependentAttributeName, true)
   5:     }
   6:     else {
   7:         alert("This function is expecting three parameters. Context, attribute name and dependent attribute name");
   8:     }
   9: }
  11: attributeOnChange(context, dependentAttributeName) {
  13:     if ((this.isValidContext(context)) && (this.isValidOptionSet(dependentAttributeName))) {
  14:         var attributeName = context.getEventSource().getName();
  15:         this.updateDependentOptionSet(attributeName, dependentAttributeName, false)
  16:     }
  17:     else {
  18:         alert("This function is expecting two parameters. Context and dependent attribute name");
  19:     }
  20: }
  22: updateDependentOptionSet(attributeName, dependentAttributeName, isFormOnLoad) {
  24:     // Get the attribute
  25:     var attribute =;
  26:     var attributeValue = attribute.getValue();
  28:     // Get the dependent attribute
  29:     var dependentAttribute =;
  30:     var dependentAttributeValue = dependentAttribute.getValue();
  31:     var dependentAttributeInitialValue = dependentAttribute.getInitialValue();
  33:     // There may be more than one control on the form for this dependent attribute, so get an array of these controls
  34:     var dependentAttributeControls = this.getAttributeControls(dependentAttributeName);
  36:     // Make sure that we actually have an array with at least one control
  37:     if ((dependentAttributeControls != "undefined") && (dependentAttributeControls != null)) {
  39:         // Loop through each control in the array
  40:         for (var i = 0; i <= dependentAttributeControls.length - 1; i++) {
  42:             // For each control, first delete all the options
  43:             dependentAttributeControls[i].clearOptions();
  45:             // Now get an array of dependent options
  46:             var dependentAttributeValues = this.getDependentAttributeValues(attributeValue);
  48:             // Make sure that we actually have an array with at least one option
  49:             if ((dependentAttributeValues != "undefined") && (dependentAttributeValues != null) && (dependentAttributeValues.length != 0)) {
  51:                 // Loop through each option in the array, and add each one to the control
  52:                 for (var j = 0; j <= dependentAttributeValues.length - 1; j++) {
  53:                     dependentAttributeControls[i].addOption(dependentAttribute.getOption(dependentAttributeValues[j]));
  54:                 }
  55:             }
  56:             else {
  57:                 dependentAttribute.setValue(null);
  58:             }
  59:         }
  60:     }
  61:     // If this is the OnLoad event we need to restore the original value of the dependent attribute, since this got wiped out earlier when we called dependentAttributeControls[i].clearOptions()
  62:     if ((isFormOnLoad) && (dependentAttributeInitialValue != "undefined") && (dependentAttributeInitialValue != null)) {
  63:         dependentAttribute.setValue(dependentAttributeInitialValue);
  64:     }
  65: }

Using the same option sets from the previous example, all I had to do was to add the country and region fields to a form, and wire up both the form OnLoad() and region field OnChange() events as shown below.

CRM 2011 Dependent Option Set Part II Example 2

CRM 2011 Dependent Option Set Part II Example 3

As before, I have selected the “Pass execution context as first parameter” checkbox, and specified the name of the relevant fields (in quotes). If you want to try this out on your own CRM 2011 environment, I have exported my solution as an unmanaged package, which you can download here.

Please note, there is a bug in CRM 2011 Beta (build 05.00.9585.101) which affects the behaviour of the Xrm.Page.ui.control.clearOptions() method, so this solution will only work if you are using CRM 2011 Release Candidate (build 05.00.9688.34).

This posting is provided “AS IS” with no warranties, and confers no rights.

Laughing Boy Chestnuts Pre-School Chain Gang

Comments (1)

  1. Bill Faulk says:

    Two notes – First, users need to know to change "srh_country" and "srh_region" in the parameters to the actual attributes used on the forms. Second, not all controls will support getAttribute() will will lead to an error in getAttributeControls. A try-catch is needed to avoid this.

               // For each control on the form, check the control attribute exists

               var attribute = null;

               try  {

                  attribute = control.getAttribute();


               catch(e) {

                    attribute = null;