Or, how to modify CRM grid pages via client script.
CRM provides 2 standard ways to add custom client script into the CRM application; via form events, and through menu items and buttons in ISV.Config. Neither of these allows you to write code to control the default views for CRM entities
However, there is a way round this. The approach is to create a host HTML (or ASP .Net) page that has no interface components itself, but contains the CRM page in an IFrame. This will appear exactly the same as the standard CRM page, but allows you to write client script in your host page that controls the CRM page, and hence change which view is displayed.
Note that this approach has to be considered as unsupported, as it involves programmatic control over a picklist outside of a CRM form.
Building the host pageThere are 2 aspects of the host page; providing the HTML to host the IFrame without adding extraneous borders or padding, and adding client script that runs once the IFrame has loaded.
The following HTML shows how to host the IFrame:
<body style="margin:0" onload="Init();"><iframe onreadystatechange="ors();" id="ifr" src="about:blank" width="100%" height="100%" frameborder="0" leftmargin="0"></body>In this example I’m creating a generic page that can host most CRM grid pages, and I’m setting the src property of the IFrame programmatically:
function Init(){var etc = getQS('etc');if (etc != null){document.all.ifr.src = '/_root/homepage.aspx?etc=' + etc;}}This src is the standard way to display most entity grids, with etc as the object type code of the entity.
I’m using the onreadystatechange event to determine whether the IFrame has loaded:
function ors()
{
if (event.srcElement.readyState == 'complete')
{
var sView = getQS('view');
if (sView != null)
SetView(sView);
document.all.ifr.style.visibility = 'visible';
}
else
{
document.all.ifr.style.visibility = 'hidden';
}
}This checks the readyState property of the IFrame, which will equal ‘complete’ when the IFrame contents have loaded, and the IFrame contents after they have been modified.
The following code shows how to modify which view is selected:
function SetView(sView)
{
var ifDoc = document.frames['ifr'].document.all; // access IFrame contents
var oSel = ifDoc['SavedQuerySelector']; // picklist control to select view
if (oSel != null)
{
var v = GetSelectValue(oSel, sView);
if (v)
{
oSel.DefaultValue = v;
oSel.DataValue = v;
oSel.FireOnChange(); // need to fire this event to apply changes
}
}
}
function GetSelectValue(oSel, sText) // helper function to select item in picklist
{
for (var i=0;i<osel.options.length;i++){
if (oSel.options[i].text == sText) return oSel.options[i].value; }
}
The code uses another helper function to access parameters passed on the query string. This function is oversimplified in that it doesn’t cope with all possible encoding issues, but is sufficient for this example:
function getQS(name)
{
var ret = '';
if (window.location.search != null && window.location.search.length > 1)
{
var aQS = window.location.search.substring(1).split('&');
if (aQS != null)
for (var i=0;i<aQS.length;i++)
if (aQS[i].indexOf(name + '=') == 0)
ret = aQS[i].substring(name.length + 1).replace('%20', ' ');
}
return ret;
}
Putting this all together, we have a page that will display an entity grid, and change the default view, based on 2 query string parameters. For example
defaultViewChanger.htm?etc=1&view=Active%20Accounts
Will display the account grid, and set the view to the Active Accounts view (%20 is the encoding of a space, which is not permitted in a url).
Setting different default views for different usersWe now have a page that can programmatically change the default view. There are 2 ways this can be used to provide different default views to different users: a programmatic way that identifies the current user (and probably team or role membership) and hence determines the default view, or via permissions in SiteMap.
I’m not intending the cover the programmatic route in detail here; my preference is to convert the page to an ASP .Net page that identifies the current user and their role, and populates the parameter to SetView in server code; an alternative approach in client code can be found
here.
Another approach is to make use of the Privilege element in SiteMap to display different navigation links to different sets of users based on their permissions, as described in more detail
here. Let’s assume we have 2 groups of users who want different default views of the account entity, group A (who are members of security role ‘roleA’) want to see My Active Accounts, and group B (members of ‘roleB’) who want to see Active Accounts.
We can create a dummy entity in CRM called exc_acctsecurity and grant roleA write rights on the exc_acctsecurity entity, and grant roleB assign rights. Then we can modify SiteMap, replacing the SubAreas for the account entity to the following:
<SubArea Id="nav_accthostA" Title="Accounts" Url="http://server/defaultViewChanger.htm?etc=1&view=My%20Active%20Accounts" Icon="/_imgs/ico_18_1.gif"><Privilege Entity="exc_acctsecurity" Privilege="Write" /></SubArea><SubArea Id="nav_accthostB" Title="Accounts" Url="http://server/defaultViewChanger.htm?etc=1&view=Active%20Accounts" Icon="/_imgs/ico_18_1.gif"><Privilege Entity="exc_acctsecurity" Privilege="Assign" /></SubArea>Note the use of XML encoding (& instead of &).
One drawback of this approach is that anybody in the System Administrator role will see both SubAreas.
A complete example of the HTML and SiteMap can be found on
CodePlex.