March 15, 2013

Dynamic navigation links using supported customizations

Consider for example the following scenario:
We need to add a link inside the left navigation panel to display an HTML Web Resource or an external URL, with CRM 2011 can easily done using the form editor as shown in the following figure



but is possible to build a dynamic URL? Yes, it is possible and more important can be done in a supported way.

First of all we create an HTML Web Resource, the page will build the dynamic URL and will display the desiderated page.
In this example we want to show the Bing results querying the name of the current account.
<html>
<head>
<script language="javascript">
function GoToDynamicUrl(accountName) {
   var dynamicUrl = "http://www.bing.com/search?q=" + accountName;
   location.href = dynamicUrl;
}
</script>
</head>
<body>
<script language="javascript">
GoToDynamicUrl('Test Account');
</script>
</body>
</html>
If we publish this Web Resource connected to a navigation link will always show the same Bing page for 'Test Account', before we can retrieve the account name from the current record we need to edit the XML definition for our navigation link.
This is a supported customization, as explained in this page:

<NavBarItem> (FormXml)

The attribute we are looking for is "PassParams", we need to add and set to 1.
To edit the XML we create a new solution containing only the Account Entity, we export as unmanaged, modify the XML as shown below, and import back to the system.
<NavBarItem Id="navLink{541067bd-4db1-2208-e5b0-a601ead56d03}" PassParams="1" Area="Info" Sequence="10"
 Icon="$webresource:msdyn_/Images/likeIcon.png" Url="$webresource:new_dynamicurl.htm">
 <Titles>
  <Title LCID="1033" Text="Dynamic Url" />
 </Titles>
</NavBarItem>
Which is the difference when we set this attribute?
This is the standard iframe src property created by CRM:
src="/%7B634988949670003339%7D/WebResources/new_dynamicurl.htm"
This is with the attribute PassParams="1":
src="/%7B634988949670003339%7D/WebResources/new_dynamicurl.htm?formid=b053a39a-041a-4356-acef-ddf00182762b&id=%7b798AA21B-DA8C-E211-A300-78E7D162EE94%7d&orglcid=1033&orgname=Organization1&pagemode=iframe&security=852023&tabSet=navLink%7b541067bd-4db1-2208-e5b0-a601ead56d03%7dArea&type=1&typename=account&userlcid=1033"
As we can see now we have new parameters available, in particular the record ID

To retrieve the data we need the Xrm Context, because we are inside a Web Resource we need to include a reference to the ClientGlobalContext.js.aspx page as explained here:

GetGlobalContext Function

For simplicity we add jQuery and use REST, the Web Resource becomes:
<html><head>
<script src="ClientGlobalContext.js.aspx" script type="text/javascript" ></script>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script language="javascript">
function GoToDynamicUrl(accountName) {
   var dynamicUrl = "http://www.bing.com/search?q=" + accountName;
   location.href = dynamicUrl;
}

function getURLParameter(name) {
   return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
}

function retrieveRecord(id, odataSetName, successCallback, errorCallback) {
   var context = Xrm.Page.context;
   var serverUrl = context.getServerUrl();
   var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
   $.ajax({
      type: "GET",
      contentType: "application/json; charset=utf-8",
      datatype: "json",
      url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')",
      beforeSend: function (XMLHttpRequest) {            
         XMLHttpRequest.setRequestHeader("Accept", "application/json");
      },
      success: function (data, textStatus, XmlHttpRequest) {
         if (successCallback) { successCallback(data.d); }
      },
      error: function (XmlHttpRequest, textStatus, errorThrown) {
         if (errorCallback) { errorCallback(errorThrown); }
      }
   });
}

function retrieveSuccess(data) {
   // we call the GoToDynamicUrl function with the Account Name 
   GoToDynamicUrl(data.Name);
}

function retrieveError(error) {
   alert("Error: " + error);
}
</script>
<meta charset="utf-8"></head><body>
<script language="javascript">
// Retrieve the id from the query string
var id = getURLParameter('id');
// Retrieve the record and call the success function
retrieveRecord(id, 'AccountSet', retrieveSuccess, retrieveError);
</script>
</body></html>
And now the result:

Notes:
  • This Web Resource can be used to show a report (calling the ReportViewer page) and pass dynamically the required parameters
  • Bing was used because Google doesn't permit to include their search pages inside an iframe

5 comments:

  1. Guido,

    is there any simple method for a non-technical person to create a link to an external URL (link Bing) and have to link name appear in the left navigation panel?

    Mel

    ReplyDelete
  2. Thanks, this is just what I need! Only difference is my dynamic URL needs an account id rather than name. The old CRM4 code was this...
    var completeURL = " http://sql01/ReportServer?/Sandbox_MSCRM/Contract+Report%20&rs:Command=Render?type=1typename=account&id=" + Xrm.Page.data.entity.getId();
    Can you tell me how to modify the web resource for the id please?

    ReplyDelete
  3. success: function (data, textStatus, XmlHttpRequest) {
    if (successCallback) { successCallback(data.d); }

    In this section of code, what is data.d???

    ReplyDelete
  4. It doesn't work, I get NOT FOUND when its calling.

    I even hardcoded the GUID of an account and used the generated URL on the browser and it works.

    Please help!!!!

    ReplyDelete
  5. Hi Jeep Ung,
    it is your CRM 2011? the first part (just show Test Accout results it is working?

    ReplyDelete