Special Thanks to my Friend cum Tech Gig Mr. Sanjaya Prakash Pradhan
Your most unhappy customers are your greatest source of learning. ~ Bill Gates
Short Talks
Microsoft allows a wide range of options to customize the Dynamics CRM application using client-side scripts like Javascript, JQuery and XRM objects. The aim of this post is to explore what all possible options and scopes are available to customize CRM system using client-side scripts. We will explore all script customization possibilities in the context of Dynamics CRM and the best practices using scripts with sample codes.
If you are a beginner in javascript then follow the below links to learn Javascript & JQuery
Learn Javascript in W3Schools and in Javascript official site
Learn JQuery in W3Schools and in official JQuery site
We will focus on below areas in this post
- Why Client-side customization is required in CRM ?
- What can we customize using Javascript, JQuery & XRM scripts ?
- How to decide whether to use Javascript vs Plugin vs Workflow ?
- How to connect CRM server from Client-side script ?
- XRM & Intensive Use of XRM object model and its methods
- Using JQuery, Javascript with Dynamics CRM
- Tools to help in client-side customization quicker
- Understanding & Managing Script Libraries and event handlers
- How to Debug client-side scripts ?
- Best reference articles on script customization.
- Client Script Customization Best Practices
- Javascript Cheat Sheets & Recommended Books
- Ready to use Common Javascript methods
- Whats new in CRM 2013/2015/2016 Scripts
- How to upgrade client scripts to run in latest versions of CRM ?
Why Client-side customization in required in CRM ?
To be honest Dynamics CRM is a web application which is built on ASP.NET at its heart and SQL Server as Database. Users interact with CRM application by different types of CRM Forms. CRM Forms are nothing but asp.net web pages which interacts with user to do specific tasks through events like OnLoad, OnSave, OnChange etc. Read the complete list of CRM Form events.
We require client-side customization for below scenarios.
- To interact with CRM database (SQL Server) in real-time
- For synchronous/Asynchronous data access
- To validate and automate CRM form fields
- To set and get CRM form field values
- To reload or refresh CRM form On-demand
- To set visibility of form fields objects
- To open external/custom hosted webpages
- To open different types of CRM Forms
- To pass parameters to custom web pages & getting return value
- To Enable/Disable form objects like Tabs, sections, controls etc.
- To check if CRM form is dirty for an instance
- To Refresh a Sub-grid on form
- To run processes (Workflows,plugins,Dialogs, Actions) from script
- To Show Notifications
- To find out the client information to write cross browser script
- To customize CRM Command/Ribbon bar with commands
- To create web javascript web resources.
- To Use javascript, JQuery with HTML web resources
Learning Script is fun
What can we customize using Javascript, JQuery, XRM scripts ?
Dynamics CRM allows various components that can be customized using client-side scripts. The below components can be customized by using client-side scripts.
- CRM Forms
- Manipulating Form Elements
- Dealing with Subgrids
- Entity Sitemap Changes
- CRM Command Bar (Application Ribbon) Editing
- Adding New Command Button with Commands
- Editing Existing Button Behavior
- Business Process Flows
- Activate Stages & Process
- Change Process Steps
- Web resources and IFrames
- Using in HTML web resources
- IFrame Custoomization
How to decide whether to use Javascript vs Plugin vs Workflow ?
As there are multiple ways to complete a task in Dynamics CRM, taking a proper decision when to use javascript and plugins, workflows etc is important and depends on the business requirement.
The below grid will help you to decide when to use Javascript, Plugins or workflows according to business demand.
Features | Workflow | JavaScript | Plugin |
Execution | Asynchronous
NOTE : In CRM 2013 and latest version we can configure real-time workflows
| Synchronous
NOTE : Can be Asynchronous by using AJAX. This will only execute on screen.
| Either |
External Data Access | No.
Note : We can only access related entity data
| Yes
Note : We can access any entity data using OData & SOAP
| Yes
Note : We can access any entity data using CRM service calls
|
Maintenance | Business Users | Programmers | Programmers |
Can Run As | User | User | CRM System/Calling User/Can be called by specific user |
On Demand | Yes
NOTE : Workflows can be called on demand by user or can be automatic by CRM events
| No | No |
Nested Child Process | Yes | No | Yes |
Executed After Saving | After | Before | Either |
Triggers | Create, Field Change, Status Change, Assign to Owner, On Demand, As a Child workflow | Field change or Form Load, Form Save, TAB Change, Command Button Press etc. | Create, Field Change, Status Change, Assign to Owner, Delete,
Update, Retrieve etc.
|
Configure/Customize | Configuration.
Note : Custom Workflow activities can be customized
| Customization.
Note: Business Rules can be configured.
| Customization only |
Entity Image Capability | No | No |
Yes
|
Note: scripts (Javascript, JQuery, XRM) only works when the user working with CRM screens like working with form.
How to connect CRM server from client-side script.
There are two ways by which we can access CRM data using javascript.
- OData (REST Protocol) endpoint (Open Data protocol)
- SOAP endpoint (Simple Object Access Protocol)
- OData (REST Protocol) endpoint
What is OData & How to Use this ?
The OData endpoint which uses REST is an architectural style in which every resource is addressed by using a unique URI. In Microsoft Dynamics CRM, a resource can be an entity collection or a record.
We can interact with CRM data using a URI passing a SQL like parameter as query string with available options or filters.
Microsoft Dynamics CRM offers a REST endpoint at below address.
[YourOrganizationURL]/XRMServices/2011/OrganizationData.svc
This URL can be copied from below section of Dynamics CRM.
Settings-Customizations->Developer Resources-> OData (REST)
This URL can be copied from below section of Dynamics CRM.
Settings-Customizations->Developer Resources-> OData (REST)
We can use the above OData endpoint to execute HTTP requests which is based on a Uniform Resource Identifier (URI). We have to use $select,$filter etc. syntax to build OData query. see the comprehensive OData system query options here .
SAMPLE CODES
A Sample OData Query looks like as below. This will retrieve account entity records with attributes Address1_Country,Address1_City,Name and Address1_Country,Address1_City in descending order where Address1_Country not equal to null and Address1_City not equal to null.
<YourODataURL>/AccountSet?$select=Address1_Country,Address1_City,Name&$orderby=Address1_Country,Address1_City desc&$filter=(Address1_Country ne null) and (Address1_City ne null)
NOTE :
Use only the schema name of the fields while writing OData Queries. Its better to useOData Query Tool to generate queries.
You need XrmServiceToolkit javascript library for this which will be added to the form script library at the top order in the entity you are working with.This library contains some major parts regarding functions.
XRMServiceToolkit can be used to make
- Common Methods: Change of CRM form like enable field, show field, etc.
- Rest EndPoint Methods: Create, Retrieve, Update a record, etc
- Soap Request Methods: Create, Retrieve, Update a record, etc
- Extension Methods: Setup Dependent OptionSet, Add Tooltip to fields, Add custom filter view to lookup field. All these methods are generic to use and configurable through editing of XML web resource.
You can also use CRM SDK library to call OData Queries
For more details you can find Sample codes to create,retrieve, update, delete using OData with Javascript with the help of CRM SDK package which includes anSDK.REST.js library that provides an example of a reusable library that can further simplify using the OData endpoint.
TOOLS FOR OData Query Builder
There are some third party tools available which helps to build OData Queries quickly using user interface options to save typing.
Find the below tools to build OData Query for your CRM application.
- OData Query Designer
- CRMRestBuilder(I personally like this because it includes to call OData & SOAP helper classes which makes my life easier)
Check how toDebug / Unit Test CRM 2011 JavaScript Rest/Soap in visual studio for on-premise CRM installation
RETRIEVE MORE RECORDS USING OData
Every time we call OData to fetch records from CRM, only top 50 records will be returned. But If there are more than 50 records, then there will be a <link rel=”next” href=”<url to next set of records>” > node in XML or a JSON__next property at the end of the result set. Here is a sample code page by Microsoft.
Although there are many advantages using OData(REST), keep in mind that the REST approach is not always the best choice to communicate with Microsoft Dynamics CRM, there are some important disadvantages and limitations to consider.
- If you need to be sure that both client and server agree on the exchange format, REST is not the best approach because it doesn’t care about types or contracts.
- It’s not a good idea sending confidential data using REST. REST protocol sends data as URIs parameters to the server, this data, even if encrypted over SSL, can be cached in the browser history and accessed by other applications and plugins in your computer.
- REST is totally stateless, if an operation needs to be continued, then REST is not the best approach, only if you need stateless CRUD operations.
- Authentication is only possible within the application and therefore limited to JavaScript and Silverlight web resources.
- The operations supported over this endpoint are limited to: Create, Retrieve, Update and Delete (CRUD). The REST philosophy does not support other operations, these operations are made using the HTTP operations PUT, GET, POST, DELETE respectively.
- Although you can select up to 12 columns using #orderby, you can only order by attributes of the root entity, or the direct relationship itself, for instance, the task owner’s name, but not the task owner’s address.
- Arithmetic, datetime and math operators are not supported.
- You can’t use multiple groups of conditions, only one.
- There’s a limit of 6 expansions using the $expand operator.
- Querying a multi-level relationship property is not supported (only one level), for instance, accessing the Owner’s telephone number from the Task entity.
- There is a maximum path length of 2048 (2KB) characters for GET requests in Internet Explorer and Safari, Opera has a 4KB limit and Firefox 8KB. This can be reached more easily than you might think if you use the $select option to query many attribute names. There is also an higher limit for POST requests. The HTTP 1.1 protocol specification states that the server might truncate the request or send a HTTP 414 error (Request-URI Too Long) if the client sends a request longer than the server expects. Try not to pass more than 2KB characters as it is the more affordable length.
- The CRM platform doesn’t use a paging cookie and limits up to 5000 total records (skip + top) when using distinct queries.
- Page size is fixed to a maximum of 50 records. It’s possible to change that in some advanced configuration settings but it’s not very straightforward.
- The OData (Open Data) protocol is not fully implemented in Microsoft Dynamics CRM 2011, the query options $inlinecount, $count and $format are not implemented.
- SOAP endpoint
Unlike the REST endpoint for web resources, the SOAP endpoint uses the Organization service. This is the same service used when writing applications that exist outside of the Microsoft Dynamics CRM 2015 and Microsoft Dynamics CRM Online 2015 Update application.
The differences are:
- Requests are sent to a different URL: <organization URL>/XRMServices/2011/Organization.svc/web.
- Authentication for web resources is provided by the application.
- If you use this endpoint outside the application, you must implement authentication. More information: Authenticate the user with the web services
Points to note:
- You can use XRMServiceToolkit library for SOAP calls
- You can SDK.soap.js library which is a part of CRM SDK for SOAP calls
With JavaScript, you will be using XmlHttpRequest to POST requests to the service. The body of the request must contain the XML appropriate for the message you are using. You must also parse the XML returned in a response. You have several options for using the SOAP endpoint with JavaScript:
sample walkthrough of SOAP usage in context of Dynamics CRM.
Software tools helpful for SOAP operations request and response checking is SOAPUI. You can easily create a request xml and post it to target service to get a quick response on the fly. I use this tool to check if for a specific SOAP request I am getting correct response or not with out debugging in Visual studio.
I personally prefer REST(OData) service to interact with CRM database. Because,
- Its simple to implement and easy to write.
- No lengthy stuff of codes
- very well structured and easy to maintain
There is already a debate going on to decide which is best to use SOAP or OData in CRM. Microsoft recommends to use SOAP and REST for below scenarios.
Task | Web Service |
Create, Retrieve, Update and Delete records. | REST Endpoint |
Associate and Disassociate records | REST Endpoint |
Assign Records | SOAP Endpoint |
Retrieve Metadata | SOAP Endpoint |
Execute Messages | SOAP Endpoint |
Here are some best article on this debate
Zsolt Blog (REST vs SOAP)
The Bottom line is :
Both REST and SOAP can be used to implement similar functionality, but in general SOAP should be used when a particular feature of SOAP is needed, and the advantages of REST make it generally the best option otherwise.
XRM & Intensive Use of XRM object model and its methods
XRM is the development platform the Microsoft Dynamics CRM application was built on. XRM object model is the Dynamics CRM’s way of interacting with Formfields.When you write form scripts you will interact with objects in the Xrm.Pagenamespace to perform the following actions:
- Get or set attribute values.
- Show and hide user interface elements.
- Reference multiple controls per attribute.
- Access multiple forms per entity.
- Manipulate form navigation items.
- Interact with the business process flow control.
The new version of CRM includes some new features and methods. Check themicrosoft page which gives a complete overview on client SDK using XRM.
Choose the correct version from the version picker to get version specific info.
The below methods are used to customize CRM forms using XRM object model in latest CRM version.
We have tried to compile all possible properties and methods available in XRM object for use.
A full list of XRM methods.
Properties/Method |
Xrm.Page.getControl(arg).showAutoComplete(object) |
Xrm.Page.getControl(arg).hideAutoComplete() |
Xrm.Page.getControl(arg).getDisabled() |
Xrm.Page.getControl(arg).setDisabled(bool) |
Xrm.Page.getControl(arg).getAttribute() |
Xrm.Page.getControl(arg).getControlType() |
Xrm.Page.getControl(arg).getName() |
Xrm.Page.getControl(arg).getParent() |
Xrm.Page.getControl(arg).getValue() |
Xrm.Page.getControl(arg).addOnKeyPress([function reference]) |
Xrm.Page.getControl(arg).removeOnKeyPress([function reference]) |
Xrm.Page.getControl(arg).fireOnKeyPress() |
Xrm.Page.getControl(arg).getLabel() |
Xrm.Page.getControl(arg).setLabel(label) |
Xrm.Page.getControl(arg).addCustomFilter(filter, entityLogicaName) |
Xrm.Page.getControl(arg).addCustomView(viewId, entityName, viewDisplayName, fetchXml, layoutXml, isDefault) |
Xrm.Page.getControl(arg).getDefaultView() |
Xrm.Page.getControl(arg).setDefaultView(viewGuid) |
Xrm.Page.getControl(arg).addPreSearch(handler) |
Xrm.Page.getControl(arg).removePreSearch(handler) |
Xrm.Page.getControl(arg).setNotification(message,uniqueId) |
Xrm.Page.getControl(arg).clearNotification(uniqueId) |
Xrm.Page.getControl(arg).addOption(option, [index]) |
Xrm.Page.getControl(arg).clearOptions() |
Xrm.Page.getControl(arg).removeOption(number) |
Xrm.Page.getControl(arg).setFocus() |
var showsTime = Xrm.Page.getControl(arg).getShowTime(); |
Xrm.Page.getControl(arg).setShowTime(bool) |
Xrm.Page.getControl(arg).refresh() |
Xrm.Page.getControl(arg).getVisible() |
Xrm.Page.getControl(arg).setVisible(bool) |
Xrm.Page.getControl(arg).getData() |
Xrm.Page.getControl(arg).setData(string) |
Xrm.Page.getControl(arg).getInitialUrl()
Returns the default URL that an IFRAME control is configured to display. This method is not available for web resources.
|
Xrm.Page.getControl(arg).getObject()
Returns the object in the form that represents an I-frame or web resource.
|
Xrm.Page.getControl(arg).getSrc()
Returns the current URL being displayed in an IFRAME or web resource.
|
Xrm.Page.getControl(arg).setSrc(string) |
context.client.getClient()
For web resources executed outside of a form, use the GetGlobalContext function to retrieve a context object.
|
context.client.getClientState() |
context.client.getFormFactor()
Use this method to get information about the kind of device the user is using.
|
context.getClientUrl() |
context.getCurrentTheme() |
context.getIsAutoSaveEnabled() |
context.getOrgLcid()
Returns the LCID value that represents the base language for the organization.
|
context.getOrgUniqueName() |
context.getQueryStringParameters() |
context.getTimeZoneOffsetMinutes() |
context.getUserId()
context.getUserLcid()
context.getUserName()
context.getUserRoles()
|
context.prependOrgName(sPath) |
Xrm.Page.data.entity.getEntityName()
Xrm.Page.data.entity.getId()
Xrm.Page.data.entity.getIsDirty()
Xrm.Page.data.entity.addOnSave([function reference])
Xrm.Page.data.entity.removeOnSave([function reference])
Xrm.Page.data.entity.getPrimaryAttributeValue()
Saves the record synchronously with the options to close the form or open a new form after the save is completed.
Xrm.Page.data.entity.save( null | “saveandclose” |”saveandnew” )
Xrm.Page.getAttribute(arg).getInitialValue()
Xrm.Page.getAttribute(arg).getOption(value)
Xrm.Page.getAttribute(arg).getOptions()
Xrm.Page.getAttribute(arg).getSelectedOption()
Xrm.Page.getAttribute(arg).getText()
Xrm.Page.getAttribute(arg).getAttributeType()
Xrm.Page.getAttribute(arg).getFormat()
Xrm.Page.getAttribute(arg).getIsDirty()
Xrm.Page.getAttribute(arg).getIsPartyList()
Xrm.Page.getAttribute(arg).getMaxLength()
Xrm.Page.getAttribute(arg).getName()
Xrm.Page.getAttribute(arg).getParent()
Xrm.Page.getAttribute(arg).getUserPrivilege()
Xrm.Page.getAttribute(arg).getMax()
Xrm.Page.getAttribute(arg).getMin()
Xrm.Page.getAttribute(arg).getPrecision()
Xrm.Page.getAttribute(arg).addOnChange([function reference])
Xrm.Page.getAttribute(arg).removeOnChange([function reference])
Xrm.Page.getAttribute(arg).fireOnChange()
Xrm.Page.getAttribute(arg).getRequiredLevel()
Xrm.Page.getAttribute(arg).setRequiredLevel(requirementLevel)
Xrm.Page.getAttribute(arg).getSubmitMode()
Xrm.Page.getAttribute(arg).setSubmitMode()
Xrm.Page.getAttribute(arg).getValue()
Xrm.Page.getAttribute(arg).setValue()
|
var activeProcess = Xrm.Page.data.process.getActiveProcess();
Xrm.Page.data.process.setActiveProcess(processId, callbackFunction);
var activeStage = Xrm.Page.data.process.getActiveStage();
Xrm.Page.data.process.setActiveStage(stageId, callbackFunction);
var stageCollection = Xrm.Page.data.process.getActivePath();
Xrm.Page.data.process.getEnabledProcesses(callbackFunction(enabledProcesses));
Xrm.Page.data.process.getSelectedStage()
Xrm.Page.data.process.addOnStageChange(handler);
Xrm.Page.data.process.removeOnStageChange(handler);
Xrm.Page.data.process.addOnStageSelected(handler);
Xrm.Page.data.process.removeOnStageSelected(function reference);
Xrm.Page.data.process.moveNext(callbackFunction);
Xrm.Page.data.process.movePrevious(callbackFunction);
var processId = procObj.getId();
var processName = procObj.getName();
var stageCollection = procObj.getStages();
var processRendered = procObj.isRendered();
var stageCategoryNumber = stageObj.getCategory().getValue();
var stageEntityName = stageObj.getEntityName();
var stageId = stageObj.getId();
var stageName = stageObj.getName();
var stageStatus = stageObj.getStatus();
var stepsCollection = stageObj.getSteps();
var stepAttributeName = stepObj.getAttribute();
var stepName = stepObj.getName();
var stepIsRequired = stepObj.isRequired();
|
Method to close the form.
Xrm.Page.ui.close()
Xrm.Page.ui.getCurrentControl()
Xrm.Page.ui.getFormType()
Xrm.Page.ui.clearFormNotification(uniqueId)
Xrm.Page.ui.clearFormNotification(uniqueId)
Xrm.Page.ui.setFormNotification(message, level, uniqueId);
Xrm.Page.ui.refreshRibbon()
navigationXrm.Page.ui.getViewPortHeight()
Xrm.Page.ui.getViewPortWidth()
|
Xrm.Page.ui.tabs.get(“tab_name”).setVisible(true/false);
Xrm.Page.ui.navigation.items.get(“navigationlink_name”).setVisible(true/false);
|
Find the complete list from Microsoft Page.
Using JQuery, Javascript in Dynamics CRM
JQuery can be used with HTML web resources to provide user interfaces because it is an excellent cross-browser library.With HTML web resources, we can control the libraries that are present and there is no restriction against manipulating the DOM. Feel free to use jQuery within your HTML Web resources. But using JQuery directly to manipulate CRM Form operation is unsupported.
The DOM object model of javascript is unsupported in Dynamics CRM form customization.JQuery is explicitly unsupported within form scripts and ribbon commands
Keep notes,
- Avoid using JQuery using in Form scripts
- Avoid using JQuery in Ribbon customization
Restrict your scripts to use the Xrm.Page and Xrm.Utility libraries available in form scripts and ribbon commands. If you decide to use the remaining capabilities of jQuery that are useful with Microsoft Dynamics CRM and include the ability to use $.ajax, consider the following:
- For best performance, don’t load jQuery in the page if you do not need it.
- Using $.ajax to perform requests against the OData and Modern Apps SOAP endpoint is supported, but there are alternatives. The alternative to using $.ajax is to use the browser’s XMLHttpRequest object directly. The jQuery $.ajax method is just a wrapper for this object. If you use the native XMLHttpRequest object directly, you do not need to load jQuery.
- Compare the SDK.REST.js and SDK.JQuery.js sample libraries found in Sample: Create, retrieve, update, and delete using the OData endpoint with JavaScript andSample: Create, retrieve, update, and delete using the OData endpoint with JavaScript and jQuery. Both perform the same operations, but SDK.REST.jsdoesn’t require jQuery.
- Each version of jQuery that is loaded in a page can be a different version. Different versions of jQuery have different behaviors and these can cause problems when multiple versions of jQuery are loaded on the same page. There is a technique to mitigate this, but it depends on editing the jQuery library and any other libraries that depend on jQuery. More information: jQuery and jQuery UI with Dynamics CRM 2011 & 2013, jQuery.noConflict()
Tools to help in client-side customization quicker
Find the below tools which will help in client side script.
- XRM ToolBox – Sitemap editor, Metadata generator etc.
- Dynamics XRM Tools
- Ribbon Workbench
- Custom code validation tool
- Useful tools for XRM
Understanding & Managing Script Libraries and event handlers
client scripts like javascript and xrm are most useful in CRM form customization.
while customizing for script we have options to add javascript web resources to the javascript library.
Javascript contains functions which is used for:
- Handle CRM Form and Field events.
- Perform actions for controls configured in the Ribbon
- Support other functions
NOTE:
- We can only add 50 script web resources for an entity into the library.After you add a library to the form, it’s available to all events in the form. For any event, you can decide which functions to be the event handlers. You can specify up to 50 functions as event handlers for any event.
- If multiple javascript webresources contains the same method name with same parameters and registered in a single library then only the method will be called which is in present in the last javascript in the orders from to in the library window.
How to debug client-side scripts ?
To debug a form script we need to follow the below steps
- Open the CRM Form which contains the script
- Press F12 which will automatically open the Script Debugger window
- Select Debugger option
- Search for your script from the folder in left top panel.
- select the required script
- go to the line of the script which you want to debug.
- do the process on the form which will trigger the function.
- you will get the debugger hit in the script.
- Press F10 to go line by line debugging
- Press F11 to go in any nested method.
- You can add any variable to watch window to check values
Best reference articles on script customization.
Follow the below links to get excellent articles and resources which will make you confident on script customization.
- MIcrosoft articles on CRM Form Programming
- CRM Book for Form events
- Upgrading CRM scripts
- Nice blog on javascript in CRM
Script Customization Best Practices
As Dynamics CRM allows a better scope using scripts there is possibility of slow performance of CRM if we will not follow the best practice of using script .
Here we have some best practices which we should follow during script customization.
- Avoid unsupported codes
- Keep the script simple
- Use safe and efficient logic
- Use Read-only and Unique values
- Use cross browser javascripts
- Do not use JQuery in form script and Ribbon editing
- Use feature detection when writing functions for multiple browsers
- Do not use DOM methods in form scripts
- Define unique names for your JavaScript functions
- Use asynchronous data access methods
Script Upgradation considerations
Using custom code validation tool we can figure out the deprecated scripts from out javascript so that we can find the alternative supported code.
How to use this tool?
To run the tool:
- Double click the downloaded file to extract the contents.
- Go to the Solutions area of your CRM organization and choose Import.
- Import the .zip file that was extracted in the first step.
- When the import is complete, click Publish and then close the import window when it’s finished.
- In the Solutions list you will now see Custom Code Validation Tool. Double click it, and then click the button to launch the tool.
- The tool will return a list of all of your Web Resources in the top left corner, the script in the middle pane and the test results in the bottom pane. A key in the top right corner will tell you how to read the results.
- Go through each web resource in the list. The items in red have to be resolved. The items in blue impact cross browser support, but should work in Internet Explorer.
Reference: Power Object