September 5, 2016

Dependent OptionSet Generator - Overview - Part 1

Some days ago I released a new Dynamics CRM tool called Dependent OptionSet Generator.
As the name suggests it helps to create and update dependent OptionSets, one of the possible approaches to filter data inside CRM UI.

Scott Durow wrote an overview about this argument on his blog: "Option-Set, Lookup or Autocomplete", it's very useful if you plan to use dependent OptionSets in order to know the pro and cons of this approach.

I want to thank Scott not only for his post but because he found the time to meet me when I was in London a couple of months ago (photo). He was the first person I talked about this little project and we had a pleasant discussion not only about Dynamics CRM, thanks again Scott!
During my short visit in London I also met again Ramón Tébar Bueno and it's really nice to spend some time with other members of the Dynamics CRM Community, plus he took me to a typical British Pub!

Now back to the main reason of this post, the Dependent OptionSet Generator.
Starting from CRM 2011 the possibility to filter OptionSets entries was available thanks to the Xrm supported methods. Microsoft also provided a solution inside their CRM SDK to implement the dependent OptionSets but the most tedious process, the generation of the XML file required to map the entries, was delegated completely to the user.

Creating manually the XML document has always been a bummer, especially when you need to deal with several entries, so developers and consultants suggest to use filtered Lookups instead.
However there are implementations where OptionSets are preferred due to the Multi-Language support, to facilitate CRM users (at eCraft, the company I work for, we often have customers with Finnish and Swedish users) or because it's required by the law (for example in some provinces of Canada).

Microsoft kept updated its Dependent OptionSet solution during the years and with the latest CRM 2016 version they changed the configuration format structure from XML to JSON, probably in order to simplify the creation of the file.

My solution consists of two parts:
  • The first part is the JavaScript Library to be included inside the CRM forms in order to filter the OptionSets
  • The second part is a Web Application to build and maintain the JSON configuration required by the JavaScript Library
This post will cover the first part, I will write another post (or more) regarding the Web Application.

The JavaScript Library included in my solution is based on the CRM 2016 SDK version called sample_SDK.DependentOptionSetSample.js, you can find the source code here. Except for the first point (Different Namespace) all the other changes were done in order to make the script compatible with CRM 2011 supported browsers.

  • Different Namespace: because I didn't change the name of the functions I preferred to use a different namespace (DO instead of SDK) in order to avoid issues if the SDK library and my library are loaded in the same form.

  • JSON: The CRM 2016 library uses JSON, but the original Microsoft Library created for CRM 2011 uses XML. When the CRM 2011 library was created Dynamics CRM supported only Internet Explorer, including old versions like IE7. These old IE versions don't have the JSON object, so (probably) they decided to parse an XML object instead. My library in order to be compatible with these IE versions includes the JSON2 library. I can include it without issues because the first line of the library checks if JSON is already defined
    if("object"!==typeof JSON)JSON={};
    
    in this way old browsers can support JSON methods like JSON.parse.

  • getClientUrl: This Xrm method was introduced with CRM 2011 UR12, but my library in order to be compatible with pre-UR12 CRM 2011 instances checks if getClientUrl is available before using it. I used this code snippet in many of my samples in order to avoid creating a JavaScript only to handle CRM 2011 versions:
    var serverUrl;
    if (Xrm.Page.context.getClientUrl !== undefined) {
        serverUrl = Xrm.Page.context.getClientUrl();
    } else {
        serverUrl = Xrm.Page.context.getServerUrl();
        if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); }
    }
    
  • response and responseText: Older versions of Internet Explorer don't implement the response property inside the object returned by the XmlHttpRequest, so if the property is not defined we will use the responseText instead.
    if (this.response !== undefined) { wrContent = this.response; }
    // handling responseText for older IE versions
    else { if (this.responseText !== undefined) { wrContent = this.responseText; } }
    
  • setTimeout: The setTimeout syntax used inside the SDK sample is not compatible with older IE versions, an easy fix is to wrap the function called inside an anonymous function:
    // original SDK sample code
    setTimeout(SDK.DependentOptionSet.filterOptions, 100, parentFieldParam, childFieldParam, dependentOptionSet);    
    // setTimeout rewritten for older IE versions
    setTimeout(function() { DO.DependentOptionSet.filterOptions(parentFieldParam, childFieldParam, dependentOptionSet); }, 100);
    
  • getClient and CRM for Tables and Phones: The SDK sample handles also the compatibility with CRM for mobile devices, but in order to handle the call to the method Xrm.Page.context.client.getClient() it's necessary to check if the context object contains the client property and its getClient method:
    if (Xrm.Page.context.client !== undefined && Xrm.Page.context.client.getClient !== undefined) {
        // ... rest of the code
    }
    
  • forEach: The SDK sample uses forEach to iterate the available values for the child OptionSet, but forEach is not available for older IE versions, the code has been rewritten to use a standard for cycle:
    //original SDK sample code
    validOptionValues.forEach(function (optionValue) { /* ... */ })
    // standard for cycle
    for (var count = 0; count < validOptionValues.length; count++) { /* ... */ }
    
Making the library compatible with CRM 2011 was more an exercise for me, CRM 2011 is officially not supported and I hope that many instances have been already migrated to newer versions, but I am aware that this is not always possible.

However the main part of my solution is the Web Application to create/update the JSON configuration, if you are already using the CRM 2016 SDK Sample in your CRM, you can use the Web Application without using my library and just update the Web Resources.

2 comments:

  1. I downloaded the solution, installed and configured a sample. But I always get an error Failed to load configuration data for dependent option sets.
    DependentOptionSet.js - on the configuration page in the solution everything works fine

    ReplyDelete
    Replies
    1. Hi Claudio, CRM version? from the error looks like it can't find the Web Resource, make sure you are setting the right name of the web resource for the DO.DependentOptionSet.init function. Feel free to send me screenshots of your script configuration at my email address (firstname.lastname@gmail.com)

      Delete