Monday, January 14, 2013

MS CRM 2011: Replacement of textbox with picklist with configurable values

During the work with CRM 4.0 I used this trick to solve similar tasks. Today I had to implement similar functionality and I decided to go supported way – JavaScript + WebResources.
Create a html webresource with following content (I called it xrm_picklist.htm):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <meta http-equiv="X-UA-Compatible" content="IE=8" />
    <style type="text/css">
        body
        {
            font-family: Segoe UI, Tahoma, Arial;
            background-color: #F6F8FA;
            font-size: 11px;
        }
        
        select.ms-crm-SelectBox
        {
            width: 100%;
            color: #000000;
            font-size: 11px;
        }
    </style>
    <script type="text/javascript" src="ClientGlobalContext.js.aspx"></script>
    <script type="text/javascript">
        function OnLoadHandler() {
            var data = GetGlobalContext().getQueryStringParameters()["data"];

            var params = {};

            var dataparts = data.split("|");
            for (var i = 0; i < dataparts.length; i++) {
                var parametersetting = dataparts[i].split("=");
                params[parametersetting[0]] = parametersetting[1];
            }

            window.picklistValues = [];
            window.sourceField = params["sourceField"];

            document.getElementById("lblValues").innerHTML = params["label"];

            window.setTimeout("window.picklistValues = window.parent." + params["getValuesFunction"] + "(); fillOptionset();", 100);
        }

        function fillOptionset() {
            var selValues = document.getElementById("selValues");

            var currentValue = window.parent.Xrm.Page.getAttribute(window.sourceField).getValue();
            var addCurrentValue = true;

            for (var i = 0; i < window.picklistValues.length; i++) {
                var newOption = document.createElement('option');
                newOption.text = window.picklistValues[i];
                newOption.value = window.picklistValues[i];

                if (currentValue != null && currentValue == window.picklistValues[i]) {
                    addCurrentValue = false;
                    newOption.setAttribute("selected", "selected");
                }

                selValues.add(newOption, null);
            }

            if (addCurrentValue && currentValue != null) {
                var newOption = document.createElement('option');
                newOption.text = currentValue;
                newOption.value = currentValue;
                newOption.setAttribute("selected", "selected");

                selValues.add(newOption, selValues.options.length == 0 ? null : selValues.options[0]);
            }
            else {
                var newOption = document.createElement('option');
                newOption.text = "";
                newOption.value = "";

                if (currentValue == null) {
                    newOption.setAttribute("selected", "selected");
                }

                selValues.add(newOption, selValues.options.length == 0 ? null : selValues.options[0]);
            }

            selValues.onchange = function () {
                window.parent.Xrm.Page.getAttribute(window.sourceField).setValue(this.value);
            };
        };
    </script>
</head>
<body onload="OnLoadHandler()">
    <table style="width: 100%; height: 100%;" cellspacing="0" cellpadding="0">
        <tr>
            <td nowrap="nowrap">
                <label id="lblValues" for="selValues">
                </label>
            </td>
            <td width="100%">
                <select id="selValues" class="ms-crm-SelectBox">
                </select>
            </td>
        </tr>
    </table>
</body>
</html>


Next step is to embed your control into form where you will use it:

You should put attention to custom parameter that is passed to your webresource - getValuesFunction=XrmSolutions.getValues|sourceField=xrm_name|label=Dynamic Optionset

getValuesFunction – the name of function that should be available in one of JS webresources of crm form.

sourceField – schema name of field to which value selected in dropdown will be saved.

label – is the label that will be shown near dropdown control.

Here is the code of JS Webresource that I used for a getValuesFunction:

if (typeof XrmSolutions == 'undefined') {
    XrmSolutions = {
        getValues: function () {
            return ["Value 1", "Value 2", "Value 3"];
        },
        __namespace: true
    };
};


In this case I used static list but you can use any kind of string array.

Here is the design of form and webresource on it:

Form and JS webresource that contains method to fill picklist:

Save and publish the form. Here is demonstration how does this functionality work: