We needed a drop down box in our CRM 4.0 environments for a lot of our clients. The data from the drop down should come from within CRM 4.0 to limit the dependencies to other systems.

The cleanest way we found to do this is via an autocomplete textbox which is actually jQuery.  To make it work we needed to get data from CRM through the CRM webservice. We did this with some helper objects that we found athttp://blogs.inetium.com/blogs/azimmer/archive/2009/02/01/crm-4-0-javascript-web-service-helper-objects.aspx. These objects are created to support a .Net like language to connect to the CRM webservice.

The next problem was an autocomplete function in JavaScript. For this we chose the functions from http://www.pengoworks.com/workshop/jquery/autocomplete.htm. We changed these a bit so there is no-more CSS included, because we did not want to load this (since the look and feel of CRM won’t change (for now)) and we don’t want to screw up the CRM classes that are already in place on the form.

How does it stick together?

Finally we needed to write some plumbing code to make it work.

In the onLoad event of the form you’ll need to add the following code:

function load_script (url) 
{ 
    var x = new ActiveXObject("Msxml2.XMLHTTP"); 
    x.open('GET', url, false); x.send(''); 
    eval(x.responseText); 
    var s = x.responseText.split(/\n/); 
    var r = /^function\s*([a-z_]+)/i; 
    for (var i = 0; i < s.length; i++){ 
        var m = r.exec(s[i]); 
        if (m != null) 
            window[m[1]] = eval(m[1]); 
    } 
} 

load_script("/Custom/ISV/jquery-1.3.2.min.js");
var scriptTag1 = document.createElement("<script src='/Custom/ISV/jquery.autocomplete.js' type='text/javascript'>");
var scriptTag2 = document.createElement("<script src='/Custom/ISV/crmHelpers.js' type='text/javascript'>");
var scriptTag3 = document.createElement("<script src='/Custom/ISV/ISVspecific.js' type='text/javascript'>");
var array = new Array();
array = document.getElementsByTagName("head");
array[0].insertAdjacentElement("afterBegin", scriptTag1);
array[0].insertAdjacentElement("afterBegin", scriptTag2);
array[0].insertAdjacentElement("afterBegin", scriptTag3);

As for the creation of the ISVspecific.js script I would like to link to a previous post a wrote on Client-side validation scripts. In that post you can see a way to create a script paste it in CRM without changing code in the events of every field on every form.

The contactFormLoad function from the previous post (Client-side validation scripts):

function contactFormLoad(){
    var zipoptions = {
                        "borderColor" : "#6699CC",
                        "selectedColor" : "#a7cdf0",
                        "background" : "white",
                        "getDataCallback" : GetCountries 
                     };
    $("#address1_country").autocomplete(zipoptions);
    //add you other onchange scripts here
}

The GetCountries which is assigned to getDataCallback is where the CRM service queries are performed. This should be your own implementation. I have prepared some sample code that retrieves countries from a small custom entity called new_country with the attributes new_countryid and new_name.

function GetCountries(partialCountry){
    try{
        var crmService = new CrmService("new_country", LOGICAL_OPERATOR_OR);
        crmService.AddColumn("new_name");
    
        if(partialCountry != null){
            crmService.AddFilterCondition("new_name", partialCountry + "%", CONDITION_OPERATOR_LIKE);
        }
        var result = crmService.Fetch(20);
        
        for(var i in result.Rows)
        {
            var s= "";
            for(var j in result.Rows[i].Columns)
            {
                s += result.Rows[i].Columns[j].Value;
            }
        }
                
        var ar = new Array();
        var i = 0;
        var addvalue = true;
        for (rowsNumber in result.Rows) {
            addvalue = true;
            var newval = result.Rows[rowsNumber].GetValue("new_name");
            for(resultRow in ar) {
                if(ar[resultRow] == newval) {
                    addvalue = false;
                    break;
                }
            }
            if(addvalue){
                ar[i] = newval;
                i++;
            }
        }
        return ar;
    }
    catch(er) {
        alert(er.message);
    }
}

As you can see in the above code block, the function takes one parameter, being the part you typed in the field you need the autocomplete functionality on. Then some fetch xml is generated by the crmHelper objects and the query is executed. This will only get 20 records as specified in the line crmService.Fetch(20).

The crmHelpers.js contains a method called CrmService.prototype.Fetch, which is a reworked version of the CrmService.prototype.RetreiveMultiple from the code of Andrew Zimmer.

If you would like to use the autocomplete function on a lookup field in CRM (yes, that also works :)) you need to add “_ledit” (without the quotes) to the fieldname. Example:

$("#new_countryid_ledit").autocomplete(zipoptions);
 
You can download a complete sample but don’t forget to create the new_country entity if you want to test.