lundi 2 novembre 2009

How to embed a report in an associated view - Crm 4.0

Hi everyone,

Some time ago, I decided to do just that: embed a report in an associated view.

This, of course, is totally and completely unsupported, and might break with the next rollup.

So, in Crm there is the entity campaign, that everyone here knows well. We have created a entity called crm_member, to record the participants to a marketing campaign. There is a one to many relationship between campaign and crm_entity. We decided to do that because heavy customizations were required, which are not possible while using only marketing lists.

So, with this new entity ready, there is now in each campaign the link to the members associated view of that campaign.

I decided to put a button in the associated view, to replace the grid with a report allowing users to have some business intelligence on these members. Indeed, there may be a fow thousand members participating to a campaign.

Here we go.

1. Set the button in the isv.config, in the entity crm_member.

<Entity name="crm_member">
  <grid>
    <MenuBar>
      <Buttons>
        <Button Icon="http://server/isv/icons/icon.gif" JavaScript="">
          <Titles>
            <Title LCID="1033" Text="" />
          </Titles>
          <ToolTips>
            <ToolTip LCID="1033" Text="Campaign Participants" />
          </ToolTips>
        </Button>
      </Buttons>
    </MenuBar>
  </Grid>
</Entity>

2. In the JavaScript="" part, set the function. Here's what I came up with to get this to work:

if (window.parent.document.all.crmForm.ObjectTypeCode!=4400)
{
  alert('You can only get detail from within an action');
}
else
{
  if (document.all.crmGrid.tagName == 'IFRAME')
  {
    document.all.crmGrid.outerHTML = outerHTML;
    document.all.crmGrid.Refresh();
  }
  else
  {
    var oId = document.all.crmGrid.GetParameter('oId');
    var reportURL = "myReportUrl";
    var frame = String.fromCharCode(60)+'iframe id='+String.fromCharCode(39)+'crmGrid'+String.fromCharCode(39)+' style='+String.fromCharCode(39)+'width:100%;height:100%;' +String.fromCharCode(39)+' src=' +String.fromCharCode(39)+reportURL+String.fromCharCode(39)+String.fromCharCode(62) + String.fromCharCode(60) + String.fromCharCode(47) + 'iframe' + String.fromCharCode(62);
    var outerHTML = document.all.crmGrid.outerHTML;
    document.all.crmGrid.outerHTML = frame;
  }
}

Explanation:

1. Get campaign id in the associated view
In this post from the excellent Customer Effective blog, we learn that this code:
document.all.crmGrid.GetParameter('oId')
is used in a grid to "get object id of main record when grid is an associated view".
So we have the campaign id.

2. We create an iframe with the report url as source.

3. Save the current html code displayed in the grid:
var outerHTML = document.all.crmGrid.outerHTML;
This code will allow us to redisplay the associated view.

4. Display our report:
document.all.crmGrid.outerHTML = frame;
So here, the html code of the crmGrid is replaced by our code, when the button is pushed.

5. Redisplay the associated view

if (document.all.crmGrid.tagName == 'IFRAME')
{
  document.all.crmGrid.outerHTML = outerHTML;
  document.all.crmGrid.Refresh();
}
When the same button is clicked again, if the crmGrid contains an iframe (our iframe), then replace the html by the previously saved html, corresponding to the associated view-grid.
Refresh the records displayed.

That's it!

dimanche 1 novembre 2009

A simple workaround to the SetFocus non sticking issue (Crm 4.0)

The Sdk is pretty clear: the SetFocus function "Sets the focus, changes tabs, and scrolls the window as necessary to show the specified field."

crmForm.all.crm_myfield.SetFocus();

At our customer, what this does is: 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 be 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 oField = crmForm.all.crm_myfield;
oField.onblur = function() {
  oField.SetFocus();
  oField.onblur = null;
}
oField.SetFocus();

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.

Untested on Crm 3.0, but probably works.

That's it!