Thursday, 1 October 2009

Hide "Add New ***" and "Add Existing ***" buttons on Associated View using JavaScript.

"Add a new **** to this record' and 'Add existing *** to this record' are default buttons which displayed in the associated views of all existing entities and for a custom entities. Sometimes, these button are not required and business demands to hide/remove them forcefully. Especially in most cases "Add a new..." button as records being created using workflows. As shown below;



After looking various options I have come accross with the JavaScript which can do the job. I have converted into generic and useful function.

Step1:
Find the name of the relationship for which you want to hide the buttons. That can be retrived from the 1:N relationships of the entity as shown in the image below;


Step2:
Copy and Paste following JavaScript functions on the OnLoad event of the entity.

function HideAssociatedViewButtons(loadAreaId, buttonTitles)
{
var navElement = document.getElementById('nav_' + loadAreaId);
if (navElement != null)
{
navElement.onclick = function LoadAreaOverride()
{
// Call the original CRM method to launch the navigation link and create area iFrame
loadArea(loadAreaId);
HideViewButtons(document.getElementById(loadAreaId + 'Frame'), buttonTitles);
}
}
}


function HideViewButtons(Iframe, buttonTitles)
{
if (Iframe != null )
{
Iframe.onreadystatechange = function HideTitledButtons()
{
if (Iframe.readyState == 'complete')
{
var iFrame = frames[window.event.srcElement.id];
var liElements = iFrame.document.getElementsByTagName('li');

for (var j = 0; j < buttonTitles.length; j++)
{
for (var i = 0; i < liElements.length; i++)
{
if (liElements[i].getAttribute('title') == buttonTitles[j])
{
liElements[i].style.display = 'none';
break;
}
}
}
}
}
}
}

[Note: for external javascript file above function can be added into common function libaray file and can be used throughout the system.]

Step3: Function Call:
Use HideAssociatedViewButtons function for each relation to hide the buttons;

HideAssociatedViewButtons('account_contacts', ['Add a new Contact to this record','Add existing Contact to this record']); //To hide both buttons.
HideAssociatedViewButtons('account_contacts', ['Add a new Contact to this record']); //To hide New button.
HideAssociatedViewButtons('account_contacts', ['Add existing Contact to this record']); //To hide Existing Button.

Hope this help. If you like this post please do comment. If you have any questions feel free to email me on irfan@irfansaeed.net or send them in comments.

Please Note: Above code is not supported by Microsoft

Triggerig/Lunch/Execute Workflow in MS CRM 4.0 using JavaScript

I have come accroess different ways to trigger workflow in JavaScript. If you remember in CRM 3.0 there used to be a class "ExecuteWFProcessRequest" which is no more available in CRM 4.0 anymore. However if you want to execute Workflow trough code in JavaScript you can use following function;

Function is very generic and can be called from anywhere such as from the Menu's, OnLoad, OnSave, OnChange etc...

Function Call:

TriggerWorkflow(EntityId, WorkFlowId);

EntityId can be found using 'crmForm.ObjectId' method or GUID of the record against which you want to trigger the Workflow i.e. you can execute any Workflow against anyrecord from anywhere.. ;)

WorkflowId is the GUID of the Workflow which you want to execute and can be obtained either from the database or by pressing "Ctrl+N" and GUID can be copied from address bar.

Function to Trigger Workflow in JavaScript:

TriggerWorkflow = function(EntityId, WorkFlowId)
{
var xml = "" +
"" +
"" + GenerateAuthenticationHeader() +
"" +
"" +
"" +
"" + EntityId + "" +
"" + WorkFlowId + "" +
"
" +
"
" +
"
" +
"
" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Execute");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
return(resultXml.xml);
}

Hope this help. If you like this post please do comment. If you have any questions feel free to email me on irfan@irfansaeed.net or send them in comments.

Note: Above code is not supported by Microsoft.

Wednesday, 30 September 2009

How to rename title of the section in MS CRM 4.0 using JavaScript

Very common business requirement where you required to rename the title of the section at run time depending on the certain attribute of the logged-in person.

Let Say: On Account Entity you want to rename "Address" section to "Billing Account" for accounts department as sown below;


I have created the following JavaScript function which can be used for any entity to update any section on any tab i.e. pretty much completely generic.

Use following code to call UpdateSectionName function;

UpdateSectionName("tab0","Address","Billing Address")
//UpdateSectionName(TabNumber,CurrentSectionName,NewSectionName)
//"tab0" means first tab and it goes like "tab1" for second tab, "tab2" for third tab and so on...

Update Section Name Functions;
Function 1:

function UpdateSectionName(TabNumber,CurrentSectionName,NewSectionName)
{
var anchorNode = document.getElementById(TabNumber);
var secBarCss = "ms-crm-Form-SectionBar";
var addrSecElm = null;

var results = getElementsByClassName( secBarCss , anchorNode );
for( var i = 0 ; i < results.length ; i++ )
{
if( results[i].innerText == CurrentSectionName)
{
addrSecElm = results[i];
break;
}
}
if(addrSecElm != null)
{
addrSecElm.innerText = NewSectionName;
}
}

Function 2:

function getElementsByClassName(className, anchorNode)
{
if(!anchorNode) anchorNode = document.body;
var result = [];
var regEx = new RegExp("\\b" + className + "\\b");
var children = anchorNode.getElementsByTagName("*");
for( var i = 0 ; i < children.length ; i++ )
{
if( regEx.test( children[i].className ) )
result.push( children[i] );
}
return result;
}

If you like my post please do not forget to give your comments.

Note: The above code is not supported by Microsoft

Wednesday, 2 September 2009

Asynchroneous Plugins Execution Error: Host CRMSERVER: failed while monitoring asynchronous operations queue. Exception: System.ArgumentNullException.

Asynchronous Plugins Execution errors are very common in MS CRM 4.0. I am sure you might have come across some in the past as well. These errors sometimes are quite hard to understand and difficult figure out what’s wrong in the plugin.

Recently I come across with the following Error in Event Log. And after lot of research I figured out there could be two potential reasons to it.
  1. Plugin Assembly is not signed
    And/Or
  2. The “Location” of the assembly in XML Plugin registration file or in Plugin Registration tool set to “Disk” instead of “Database”. I did not managed to find out any valid reason why ‘Disk’ option not worked well.

Comments from other bloggers are welcomed. If you think this post really helped to solve your issue please do comment. Thanks.

Error in Event Log
Host CRMSERVER: failed while monitoring asynchronous operations queue. Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: fileName
at System.IO.FileInfo..ctor(String fileName)
at Microsoft.Crm.Extensibility.PluginAssemblyFactory.IsFileNameOnly(String fileName)
at Microsoft.Crm.Extensibility.PluginAssemblyFactory.LoadAssembly(String assemblyFile)
at Microsoft.Crm.Extensibility.PluginAssemblyFactory.CreateInstance(Guid pluginAssemblyId, IOrganizationContext context)
at Microsoft.Crm.Caching.PluginAssemblyCacheLoader.LoadCacheData(Guid key, IOrganizationContext context)
at Microsoft.Crm.Caching.CrmMultiOrgCache`2.CreateEntry(TKey key, IOrganizationContext context)
at Microsoft.Crm.Caching.CrmSharedMultiOrgCache`2.LookupEntry(TKey key, IOrganizationContext context)
at Microsoft.Crm.Caching.PluginTypeCacheLoader.LoadCacheData(Guid key, IOrganizationContext context)
at Microsoft.Crm.Caching.CrmMultiOrgCache`2.CreateEntry(TKey key, IOrganizationContext context)
at Microsoft.Crm.Caching.CrmSharedMultiOrgCache`2.LookupEntry(TKey key, IOrganizationContext context)
at Microsoft.Crm.Caching.PluginTypeCache.LookupEntry(Guid pluginTypeId, IOrganizationContext context)
at Microsoft.Crm.Asynchronous.AsyncOperationCommand.GetPluginType(Guid pluginTypeId)
at Microsoft.Crm.Asynchronous.EventOperation.InternalExecute(AsyncEvent asyncEvent)
at Microsoft.Crm.Asynchronous.AsyncOperationCommand.Execute(AsyncEvent asyncEvent)
at Microsoft.Crm.Asynchronous.AsyncHostHandler.Handle(AsyncEvent asyncEvent)
at Microsoft.Crm.Asynchronous.QueueManager.PoolHandler.ProcessAsyncEvent(AsyncEvent asyncEvent)
at Microsoft.Crm.Asynchronous.QueueManager.PoolHandler.InvokeHandlerInPool(Object state)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

Monday, 31 August 2009

How to find roles of the logged-in user in MS CRM 4.0 using JavaScript

Few days ago I come across with the business requirement where I was required to find out if logged-in user has particular role or not. Let say:

If (Logged-In User has Role ‘Marketing Executive’ and Marketing Letter status = Published)
{
Show Marketing Fields
}
else
{
Hide Marketing Fields
}

This kind of business requirements cannot be fulfilled using out of box CRM Security Model. After little research on internet I come across with different examples which allows user to find out if user has particular role or not. I merged those examples into easy to use function.

Function returns all the roles of the Current Logged-In User.

function GetCurrentUserRoles()
{
var xml = "" +
"" +
"" +
GenerateAuthenticationHeader() +
" " +
" " +
" " +
" role" +
" " +
" " +
" name" +
"
" +
"
" +
" false" +
" " +
" " +
" roleid" +
" role" +
" systemuserroles" +
" roleid" +
" Inner" +
" " +
" " +
" systemuserid" +
" systemuserroles" +
" systemuser" +
" systemuserid" +
" Inner" +
" " +
" And" +
" " +
" " +
" systemuserid" +
" EqualUserId" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"
" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction"," http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
return(resultXml);
}

Function which calls the above function and search for indivisual role:

function UserHasRole(roleName)
{
//get Current User Roles, oXml is an object
var oXml = GetCurrentUserRoles();
if(oXml != null)
{
//select the node text
var roles = oXml.selectNodes("//BusinessEntity/q1:name");
if(roles != null)
{
for( i = 0; i < roles.length; i++)
{
if(roles[i].text == roleName)
{
//return true if user has this role
return true;
}
}
}
}
//otherwise return false
return false;
}

How to use UserHasRole function:

if(UserHasRole(“System Administrator”) == true)
{
alert(‘User has admin role’);
}
else
{
alert(‘User does not have admin role’);
}

Hope this helps. Please drop comments if script is helpful.

Note: The above code is not supported by Microsoft.

Thursday, 28 May 2009

Change Field/Attribute requirement at runtime using javascript

Some times you come across with the situation when you have to make field mandatory on the form at runtime. Let say on selection of one field other field become required and if selection change field become business recommended or not required anymore.

On possible way is to use if-else statement to check if field.DataValue == null or not and respond accordingly. But following code can be used to make fields not required, required and business recommended.


crmForm.SetFieldReqLevel("fieldname",0);// set field to not required
crmForm.SetFieldReqLevel("fieldname",1); // set field to required/mandatory
crmForm.SetFieldReqLevel("fieldname",2); // set field to business recommended
Hope this helps. Please drop some comments if script is helpful.

Note: The above code is not supported by Microsoft.

Tuesday, 5 May 2009

A time-out issue on importing customization file and/or on execution of Plugins

A very common issue when user import large customization file into MS Dynamics CRM 3.0 or into MS Dynamics CRM 4.0 the user get time-out error. Sometimes same issue occurs for smaller customization files if database is too large.

In some cases it has been noticed that if database it too large users gets similar error on the execution of normal operations especially like on execution of custom plugins and custom workflow activities.

User get errors like:
  • import timeout error.
  • Microsoft CRM Platform Error Report: Error Description: Timeout expired Error Details: Details on this error have not been provided by the platform. Error Number: 0x80040E31
Microsoft suggested few solutions to fix this issue among which is to add the OLEDBTimeout and ExtendedTimeout registry subkeys to increase the time-out values, which work incredibly well for me.

Refer:
http://support.microsoft.com/kb/918609

I have created .reg file and uploaded into Sky drive which adds these values into registry.

How to Add subkeys using .reg file:
Hope this helps. Please drop some comments if solution is helpful.

Note: If error is vague and does not make any clear sense then user can enable tracing. Please refer to my next blog which is regarding how to enable tracking in MS CRM Dynamics.