vendredi 30 octobre 2009

Set Focus on a field when opening record from srs report

Hi everyone,

With Crm 4.0, a customer recently asked me to develop a new report with Sql Server Reporting Services, that would display different records from an entity, with the fields belonging mainly to that entity. Each field should be a link to the corresponding record.

Here's the interesting part: when clicking on a particular field, the record should open with the focus set on that field.

Remember that if you have multiple tabs, simply setting the focus on the field you want will have the correct tab displayed.

So, 4 steps here :

1. First, the links in the report.
2. How to say to a crmForm which field to set focus on?
3. Retrieve the value in crmForm
4. Set the focus on that field

Let's go!

1. First, the links in the report.

As a small reminder, here's an exemple:

="http://crm/myorg/userdefined/edit.aspx?id={" + Fields!entityid.Value.ToString() + "}&etn=crm_myentity"

Notice the use of etn (Entity Type Name), much preferable to etc (Entity Type Code), which is a number and changes between crm implementations, thus from dev to prod for example.

2. How to say to a crmForm which field to set focus on?

As explained in the sdk, when you open a new form, using the URL address you can include arguments in the query string to set field values. The following requirements must be met:
  • The names of the query string arguments must match or include the names of attributes for the entity.
  • Lookup and Customer lookup fields should use the suffix 'name' with the attribute name to set the text to display.
  • Customer lookup fields must use the suffix 'type' with the attribute name to set whether the reference is to an account or a contact.
  • The values passed must be valid.
  • The value cannot be a script.
Note: This does not work with activities.

So, now we know it is possible to pass values to a crmForm, the only condition being that the parameter name must be the name of an existing attribute.
Thus, create a new varchar attribute, with enough chars for your needs.
Example: crm_focus. No need to put the attribute on the form!

Now, we can change the url in the report to this:

="http://crm/myorg/userdefined/edit.aspx?id={" + Fields!entityid.Value.ToString() + "}&etn=crm_myentity&crm_focus=cm_attribute_to_focus"

Note: when you try to pass a parameter name that is not the name of an attribute, crm will just open the error form.

3. Retrieve the value in crmForm

For this, 2 possible solutions that I know of.

A. Use gup (Get Url Parameter) function, that you find about anywhere on the net, here for example.

function gup( name )
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
return results[1];
So in the onload of your crmForm, just use :

var focus = gup('crm_focus');

B. See this page on StunnWare, where Crm Mvp Michael Höhne, among other things, describes a nice ParseQueryString() function, which results in this:

var QueryString = ParseQueryString();
var template = QueryString["template"];

On that page, Michael gives other nice and interesting JavaScript tricks, worth a read.

4. Set the focus on that field

So, here we go. In my focus variable, I have the name of the field. So, I try to use the crm function SetFocus, defined in the Sdk :

var oField = document.getElementById(focus);

Horror! When the form opens, the focus is changed only for like one milisecond or so and then switches back to default focus, first tab, first field I think.
This bug is supposed to fixed since Update Rollup 1 for Crm 4.0. There is a specific hotfix included in that rollup. And for the record, there was the exact same bug in Crm 3.0, here is the kb. Problem, the issue still happens at the customer, so I have to fix it.

Not so easy to solve at first sight. But after some good thinking, here's the solution I came up with :

var focus = gup('crm_focus');
var oField = document.getElementById(focus);
oField.onblur = function() {
  oField.onblur = null;

Word of explanation: the onblur event is triggered when an element loses the focus.
So, crmForm loads, I call SetFocus, the field receives the focus and after one milisec loses it. So the bug has been executed. Then, onblur is called, and the field gets the focus again. To allow the user to click on other field, remove the onblur event. This is a quite simple and effective workaround.

That's it!!