Useful CRM Tips

Useful CRM Tips...

Friday, June 29, 2012

Change Url of Left Navigation Pane Link at runtime in CRM 2011

You can change the Url of Left Navigation Pane link dynamically.

To explain this i take an scenerio that i have a entity, in this i have an custom left navigation pane link which loads an external URL, here i consider that as Google. Now dynamically i want to change that URL to my Blog URL. We can achieve this by the below code:


the function loadIsvArea(Mscrm.CrmUri.create(iframeUrl),false) is responsible for achieving this.
//Get all navigation items for this form.
var items = Xrm.Page.ui.navigation.items.get();

//Go through the list of navigation items.
for (var i in items)
{
  //Get the current navigation item in the for loop
  var item = items[i];
  //Get the label of the current navigation item
  var itemLabel = item.getLabel();
 
  //Check if this is the navigation item we are looking for using the label name.
  if(itemLabel == "Custom Link")
  {
    //Get the current navigation item id.
    var areaId = item.getId();
 //Get navigation element by using the id.
    var navElement = document.getElementById(areaId);
    //Make sure that the navigation element is not empty or null
    if (navElement != null && navElement != undefined)
    {
    //Create the url to use in the navigation link
    var iframeUrl = encodeURI("http://mscrmessentialblog.blogspot.com/");
    //Create a function that is run when the navigation link is clicked.
 navElement.onclick = function ()
    {
      //Start by creating the area, this is where the url looses "/report/path" from the path.
      loadIsvArea(Mscrm.CrmUri.create(iframeUrl),false);
      //Get the iframe in the navigation area.
      var navIframeObject = document.getElementById(areaId+"AreaFrame");
      //Set the source for the iframe again with the correct url.
      navIframeObject.src = iframeUrl;
    };
    }
  }
}

This results as:

Create a Custom Group in Entity Ribbon Main Tab

For this, I have opted the WorkRequest(custom Entity), in this entity ribbon am going to create a new custom group and place three custom buttons in that.

for this first we need to export the customization of that entity then edit the
RibbonDiffXml of that entity as follows.

In the <CustomActions/> node place this code to create the new custom group on the main tab of the respective entity and also add custom buttons to that group

then define the command definations (which also contains the actions to be peformed by the custom buttons) for the controls(buttons) & custom group as we declared above
<CustomActions>
          <CustomAction Id="Mscrm.Form.new_work_request.CustomGroup.CustomAction"
                        Location="Mscrm.Form.new_work_request.MainTab.Groups._children"
                        Sequence="110">
            <CommandUIDefinition>
              <Group Id="Mscrm.Form.new_work_request.CustomGroup.Group"
                      Command="Mscrm.Isv.new_work_request.Form.Group0"
                      Title="ISV WorkRequest Button Group"
                      Sequence="51"
                      Template="Mscrm.Templates.Flexible2">
                <Controls Id="Mscrm.Form.new_work_request.CustomGroup.Controls">
                  <Button Id="Mscrm.Form.new_work_request.Form.Group0.Control0"
                          Command="Mscrm.Isv.new_work_request.Form.Group0.Control0"
                          LabelText="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control0.LocLabel"
                          ToolTipTitle="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control0.LocLabel"
                          ToolTipDescription="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control0.LocLabel"
                          Image16by16="/_imgs/ribbon/customaction16.png" Image32by32="/_imgs/ribbon/customaction32.png"
                          Image16by16Class="ms-crm-Upgraded-Ribbon-Image16"
                          Image32by32Class="ms-crm-Upgraded-Ribbon-Image32"
                          Sequence="10"
                          TemplateAlias="o1" />
                  <Button Id="Mscrm.Isv.new_work_request.Form.Group0.Control1"
                          Command="Mscrm.Isv.new_work_request.Form.Group0.Control1"
                          LabelText="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control1.LocLabel"
                          ToolTipTitle="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control1.LocLabel"
                          ToolTipDescription="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control1.LocLabel"
                          Image16by16="/_imgs/ribbon/customaction16.png"
                          Image32by32="/_imgs/ribbon/customaction32.png"
                          Image16by16Class="ms-crm-Upgraded-Ribbon-Image16"
                          Image32by32Class="ms-crm-Upgraded-Ribbon-Image32"
                          Sequence="10"
                          TemplateAlias="o1" />
                  <Button Id="Mscrm.Isv.new_work_request.Form.Group0.Control2"
                          Command="Mscrm.Isv.new_work_request.Form.Group0.Control2"
                          LabelText="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control2.LocLabel"
                          ToolTipTitle="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control2.LocLabel"
                          ToolTipDescription="$LocLabels:Mscrm.Isv.new_work_request.Form.Group0.Control2.LocLabel"
                          Image16by16="/_imgs/ribbon/customaction16.png"
                          Image32by32="/_imgs/ribbon/customaction32.png"
                          Image16by16Class="ms-crm-Upgraded-Ribbon-Image16"
                          Image32by32Class="ms-crm-Upgraded-Ribbon-Image32"
                          Sequence="10"
                          TemplateAlias="o1" />
                </Controls>
              </Group>
            </CommandUIDefinition>
          </CustomAction>
          <CustomAction Id="Mscrm.Form.new_work_request.CustomGroup.MaxSize.CustomAction"
                        Location="Mscrm.Form.new_work_request.MainTab.Scaling._children"
                        Sequence="120">
            <CommandUIDefinition>
              <MaxSize  Id="Mscrm.Form.new_work_request.CustomGroup.MaxSize"
                        GroupId="Mscrm.Form.new_work_request.CustomGroup.Group"
                        Sequence="21"
                        Size="LargeLarge" />
            </CommandUIDefinition>
          </CustomAction>
          <CustomAction Id="Mscrm.Form.new_work_request.CustomGroup.Popup.CustomAction"
                        Location="Mscrm.Form.new_work_request.MainTab.Scaling._children"
                        Sequence="140">
            <CommandUIDefinition>
              <Scale    Id="Mscrm.Form.new_work_request.CustomGroup.Popup.1"
                        GroupId="Mscrm.Form.new_work_request.CustomGroup.Group"
                        Sequence="85"
                        Size="Popup" />
            </CommandUIDefinition>
          </CustomAction>
        </CustomActions>

also define the command definations for the custom ribbon buttons as we declared above.

<CommandDefinitions>
          <CommandDefinition Id="Mscrm.Isv.new_work_request.Form.Group0">
            <EnableRules />
            <DisplayRules />
            <Actions />
          </CommandDefinition>
          <CommandDefinition Id="Mscrm.Isv.new_work_request.Form.Group0.Control0">
            <EnableRules />
            <DisplayRules>
              <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control0" />
            </DisplayRules>
            <Actions>
              <Url Address="/../Castweb/Issues/ISF.aspx?source=new_work_request&amp;OrderTypeId=2" PassParams="true" />
            </Actions>
          </CommandDefinition>
          <CommandDefinition Id="Mscrm.Isv.new_work_request.Form.Group0.Control1">
            <EnableRules />
            <DisplayRules>
              <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control1" />
            </DisplayRules>
            <Actions>
              <Url Address="/../Castweb/Issues/ISF.aspx?source=new_work_request&amp;OrderTypeId=1" PassParams="true" />
            </Actions>
          </CommandDefinition>
          <CommandDefinition Id="Mscrm.Isv.new_work_request.Form.Group0.Control2">
            <EnableRules />
            <DisplayRules>
              <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control2" />
            </DisplayRules>
            <Actions>
              <Url Address="/../Castweb/Issues/ISF.aspx?source=new_work_request&amp;OrderTypeId=3" PassParams="true" />
            </Actions>
          </CommandDefinition>
        </CommandDefinitions>

also define the rule definations for the custom ribbon buttons as we declared above.

<RuleDefinitions>
          <TabDisplayRules>
          </TabDisplayRules>
          <DisplayRules>
            <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control0">
              <FormStateRule State="Create" InvertResult="true" />
            </DisplayRule>
            <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control1">
              <FormStateRule State="Create" InvertResult="true" />
            </DisplayRule>
            <DisplayRule Id="Mscrm.Isv.new_work_request.Form.Group0.Control2">
              <FormStateRule State="Create" InvertResult="true" />
            </DisplayRule>
          </DisplayRules>
          <EnableRules />
        </RuleDefinitions>

and also define the local labels as we declared above.
<LocLabels>
          <LocLabel Id="Mscrm.Isv.new_work_request.Form.Group0.Control0.LocLabel">
            <Titles>
              <Title languagecode="1033" description="Display" />
            </Titles>
          </LocLabel>
          <LocLabel Id="Mscrm.Isv.new_work_request.Form.Group0.Control1.LocLabel">
            <Titles>
              <Title languagecode="1033" description="Search" />
            </Titles>
          </LocLabel>
          <LocLabel Id="Mscrm.Isv.new_work_request.Form.Group0.Control2.LocLabel">
            <Titles>
              <Title languagecode="1033" description="Technology" />
            </Titles>
          </LocLabel>
        </LocLabels>


finally a custom group with some custom buttons is defined under the main tab of the entity & looks like below.

Tuesday, June 26, 2012

Cross Domain Issue while working with CRM 2011 Web Services in JScript

Recently I faced a “Cross Domain” issue while working with Jscript ODATA query. Below is the code which I have used:

var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";

var context = GetGlobalContext();

var serverUrl = context.getServerUrl();

//Asynchronous AJAX function to Retrieve a CRM record using OData

$.ajax({

type: "GET",

contentType: "application/json; charset=utf-8",

datatype: "json",

url: serverUrl + ODATA_ENDPOINT + "/AccountSet?$filter=Address1_City eq 'Redmond'",

beforeSend: function (XMLHttpRequest)

{

XMLHttpRequest.setRequestHeader("Accept", "application/json");

},

success: function (data, textStatus, XmlHttpRequest)

{

// Success Call Back

},

error: function (XmlHttpRequest, textStatus, errorThrown)

{

// Error Call Back

}

});

The REST End point “url “ which I am passing in the above code is: http://<server>/<orgname>/XRMServices/2011/OrganizationData.svc/AccountSet?$filter=Address1_City eq 'Redmond'.This code only works when we open CRM records using CRM “Server” name. It fails in other cases like when we open it using IP Address or localhost. The primary reason for this is due to “Cross Domain Policy”. The blocker is the REST End point which we are using.

So, I thought of replacing server name with IP Address as follows.


I ran it in the browser.... It worked...!!!! J

So, I got a simple solution.

Use the following instead of getting “ServerUrl” from the context object.

var serverUrl = window.location.protocol + "//" + window.location.host + "/" + context.getOrgUniqueName();

Here we just need to use the window.location property to get the current window protocol and host and build the REST Endpoint.

Hope it helps...!!!! Please let me know if we have any other alternative solution.

Friday, June 22, 2012

Retrieve Server Datetime on the client in CRM 4.0

There are many ways to achieve that, the following are he ways to do so.
1. Create custom aspx page.
2. Create custom webservice.
3. Use standard Microsoft CRM WebServices for this task.
The first and the second ways were not interesting for me because I had already used in some tasks I'd made. So I decided to implement the third idea.

So the points:
1. Create the plugin which will handle Execute message (Fetch from client side) and insert server datetime in the response XML.
2. Write client side JavaScript code which will execute this Fetch request, retrieve the result XML and parse it.

Plugin code (Registration: Message - Execute, Primary Entity - none, Secondary Entity - none, Stage of Execution - Post Stage, Execution Mode - Synchronous, Triggering Pipeline - Parent Pipeline):

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using System.Xml;

namespace TimePlugin
{
    public class ExecuteXMLParser : IPlugin
    {
        #region IPlugin Members
        public void Execute(IPluginExecutionContext context)   
     {
            if (context.MessageName == "Execute" && context.OutputParameters.Contains("FetchXMLResult"))
            {
                //I retrieve response XML
                string result = (string)context.OutputParameters.Properties["FetchXMLResult"];
                XmlDocument document = new XmlDocument();
                //Load this XML into XMLDocument
                document.LoadXml(result); 
                //Create and add attribute with current date time
                XmlAttribute timeAttribute = document.CreateAttribute("ServerDateTime");
                timeAttribute.Value = DateTime.Now.ToString("yyyy.MM.dd.hh.mm.ss");
                document.FirstChild.Attributes.Append(timeAttribute);
                //Place modified result XML to context to be returned to client
                context.OutputParameters["FetchXMLResult"] = document.OuterXml;
            }
        }
      
#endregion IPlugin Members
    }
}

Client side JavaScript (You can use any fetch request you have): 
//Create simple Fetch xml request
var xml = "<?xml version='1.0' encoding='utf-8'?>"+
"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'"+
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"+
" xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"+
GenerateAuthenticationHeader()+
"<soap:Body>"+
"<Fetch xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<fetchXml>&lt;fetch mapping='logical'&gt;"+
"&lt;entity name='systemuser'&gt;"+
"&lt;no-attrs/&gt;"+
"&lt;filter type='and'&gt;"+
"&lt;condition attribute='systemuserid' operator='eq-userid'/&gt;"+
"&lt;/filter&gt;"+
"&lt;/entity&gt;"+
"&lt;/fetch&gt;</fetchXml>"+
"</Fetch>"+
"</soap:Body>"+
"</soap:Envelope>";

//Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Fetch");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
//Capture the result
var resultSet = xHReq.responseXML.text;
resultSet.replace('&lt;','<');
resultSet.replace('&gt;','>');
//Create an XML document that can be parsed.
var oXmlDoc = new ActiveXObject("Microsoft.XMLDOM");
oXmlDoc.async = false;
oXmlDoc.loadXML(resultSet);
//Value the user is interesed in in string form
var datetime = oXmlDoc.selectSingleNode('resultset').getAttribute('ServerDateTime').split(".");
//And the result - Date object
var result = new Date();
result.setFullYear(datetime[0]);
result.setMonth(datetime[1] - 1);
result.setDate(datetime[2]);
result.setHours(datetime[3] - 1);
result.setMinutes(datetime[4]);
result.setSeconds(datetime[5]);

alert(result);


Wednesday, June 20, 2012

Force Submit Alternative in CRM 2011

As there is the way to Force submit a field in CRM 4.0 there is an alternative way in the CRM 2011 to achieve the same.
 Xrm.Page.getAttribute("fieldName").setSubmitMode("always");
There are three possible ways to submit the attribute:

• always
• never
• dirty