Monday, June 1, 2009

Overriding and Filtering Multiple Record Lookup Form for Microsoft Dynamics CRM 4.0

Warning: This will require some javascript and html coding knowledge, and one of Dynamics javascript files must be modified for this to work. Make sure you make backups of any files before modifying them.

One of the big limitations in Dynamics, is the inability to do any type of filtering or custom columns for the multi lookup form. I had a request from our support team to pre-filter the lookup results for contacts on the email forms To, CC, and BCC fields to only show contacts that are linked to the account that the regarding case is linked too. Without this they have to either open up the account and select contacts to find them, or do an advanced find lookup, both of which are a massive time waist for them and also prone to possible errors since they would have to then remember those contacts and go searching for them in the multi lookup form on the email. And we have far too many contacts and accounts for them to be expected to remember them by name when they are doing the lookup on the existing lookup form.

Unfortunately there is no built in or supported method for doing this, but I believe there is some third party tools out there to make this somewhat possible (Stunnware has something that looked useful and very well done). I decided to go down the road of trying to hijack the lookup window from Dynamics and display my own form, so that I can provide some highly customized functionality for their needs instead of trying to make something else work in our special way.

I first opened up the new email form in IE8 and attached the built in debugger (F12) and started profiling into what actually happens when you click the lookup glass image for the To and other multi lookup fields.

The To, CC, and BCC fields call the LookupObjects() method in wwroot\_static\_controls\Lookup.js which will build a url for what form to use. Since this does this based on a property on the field itself, I decided to use this to open my form instead and not require special code to handle my forms results. Here is the section of the LookupObjects() method we will take advantage of:

url = prependOrgName("/_controls/lookup/lookup");
url += lookupStyle;
url += ".aspx";
url += "?class=" + lookupClass;
url += "&objecttypes=" + lookupTypes;
url += "&browse=" + lookupBrowse;

As you can see, the lookupStyle is the property on the field we can change from “multi” to our own value (“multiaz” in my case) and then place an appropriately named file “LookupMultiAz.aspx” in that same directory (/_controls/lookup/) and it won’t require a modification of this method to get our custom form, or of the result handling.

Unfortunately we can’t just get away with modifying the fields lookup style attribute to point to our new form. Dynamics makes a call to the BuildFeatures() method in that same Lookup.js file to determine the sizing of the lookup window it’s about to open, and it will alert and stop your window from opening if it does not know about your new lookup style. So with a simple modification to the switch statement in the method, we can add our lookup style.
WARNING: This is not supported and you are modifying this file at your own risk! Make a backup copy first!

function BuildFeatures(lookupStyle) {
var oFeatures = new Object();

switch (lookupStyle) {
case "multiaz":
oFeatures.height = "460px";
oFeatures.width = "650px";
break;
case "multi":
oFeatures.height = "460px";
oFeatures.width = "600px";
break;
case "single":
oFeatures.height = "488px";
oFeatures.width = "600px";
break;
case "subject":
oFeatures.height = "450px";
oFeatures.width = "500px";
break;
default:
alert(LOCID_LOOKUPSTYLE_NOT_SET + lookupStyle);
return null;
}

return oFeatures;
}

Next we need to make a new form/web page to replace the LookupMulti.aspx used by Dynamics. You must name this page Lookup[CustomStyle].aspx (replace [CustomStyle] with the name you chose in the previous steps, “multiaz” for me so “Lookupmultiaz.aspx”). In this page you will need to implement your own custom lookup and record selection to replace the Dynamics multi lookup form. Here is an example of the custom form that I designed for our support team based on their criteria:


To make your form work with Dynamics you need to pass back the records in the same format that Dynamics is expecting to get them in. Dynamics expects to get back the LookupItem object from LookupDialogs.js file (same location as Lookup.js), which you can re-use by adding a reference to it in your custom page. I chose to just copy the LookupItem() function to my form instead of referencing the file since I didn’t need anything else in there. As there is no real type safety in javascript, the object you return just needs to contain the correctly named properties.

function LookupItem() {
this.id = "";
this.name = "";
this.html = "";
this.type = "";
this.values = null;
this.keyValues = null;
this.category = null;
this.ambiguousRecordsXml = null;
}

The only properties that need to be filled out for each LookupItem is:
id = the record id (guid)
name = name of the record (John Doe)
html = html to display the record

type = type code for the record (contact = 2, system user = 8, account = 1, etc)

Then add each LookupItem to the items property on an object and return it by setting the value to window.returnValue when ready.

var lookupItems = { items: new Array() };
var item = new LookupItem();
item.id = ‘{479ECE53-099D-4fe5-92AE-AAA13659E7AC}’;
item.type = 2;
item.name = ‘John Doe’;
item.html = ‘<NOBR><IMG class=ms-crm-Lookup-Item alt="" src="/_imgs/ico_16_2.gif">John Doe</NOBR>’;
lookupItems.items.push(item);

window.returnValue = lookupItems;
window.close();

The other thing your form will need to handle is if the field already has values and the user opens your custom form, those values will be passed to your form by Dynamics using the dialogArguments property.

var args = this.dialogArguments;
for (var i = 0; i < args.items[i]; i++){
var recordHtml = args.items[i].innerHTML;
var recordId = args.items[i].getAttribute('oid');
var recordType = args.items[i].getAttribute('otypename');
//Do something with the record now
}

In your custom form you will need to query dynamics to retrieve records to present to the user, this can be done many ways and I wont get into that here. In my example I use a javascript library from Asenctium to interact with Dynamics that handles the SOAP mess, and the ExtJs framework for building my form and the interactions.

Happy coding!

No comments:

Post a Comment