CRM JavaScript Best Practices

The use of JavaScript in Dynamics CRM 2011 allows you to manipulate CRM forms and data in real time using lightweight and easy to use syntax. Because JavaScript is commonly used in web development, it has been heavily extended with methods that allow developers virtually limitless possibilities. This does not, however, mean that all tools available should be applied to Dynamics CRM environments. Jump to the following sections to to learn some do’s and don’ts for JavaScript customizations:

Avoid unsupported code

Examples of JavaScript functions and patterns can be found all over the internet, but just because something works on a custom web page does not mean it should be utilized within CRM.  Most of the functions required to carry out tasks in CRM can be accessed from the Xrm.Page context.  Methods within this object model allows you to perform actions like change data in fields, show or hide fields or form tabs, and even raise simple events.  As a general rule, any function not available through the Xrm.Page context should be considered unsupported and used with caution if not avoided altogether.  Should you chose to use unsupported JavaScript functions in your libraries you could see issues like broken forms, error messages, failed logic, and even corrupted data.  The Custom Code Validation Tool can help identify unsupported code in your organization.

Some commonly used JavaScript features and functions that are unsupported in CRM 2011 are:

  • .getElementById() – Although this method may not fail, it is commonly used for DOM manipulation which is not supported in CRM.  As best practice it should be avoided.
  • JQuery – This powerful JavaScript library provides helper methods that allow developers to do just about anything they want with JavaScript with a very small footprint.  Although it is not officially supported, versions of JQuery are shipped with the Dynamics CRM 2011 SDK The mechanics behind its powerful methods may carry out unsupported actions and therefore result in errors.  Use with caution.
  • crmForm Object Model – This syntax was the official object model of CRM4.0 but is no longer supported with CRM 2011 Update Rollup 12 and newer.  Methods using this syntax are prone to failure in these versions and can fail without producing error messages.
  • .FireOnChange() – Like the crmForm object model, this method has been depreciated.  The .fireOnChange() method (with a lower case ‘f’) is available through the Xrm.Page context and should be used instead.

Keep It Simple

  • Keep your libraries as small as possible

JavaScript libraries are stored in web resources and requested by the form each time a form is loaded.  This means that each time the form for a record is opened every JavaScript library tied to that form is downloaded from CRM’s web resource table.  Keep your libraries as simple and as clean as possible.  This will increase performance and improve maintainability.  Simple things like keeping commented lines to a minimum and removing unused libraries from the form can go a long way towards increasing performance.

  • Make sure your libraries are readable

One of the most important things to remember when developing JavaScript libraries is to make sure that you or anyone else that may see your libraries in the future can read the code you’ve written.  In your pursuit to shrink the size if your libraries you may be tempted to remove line breaks or employ tools such as JavaScript minifiers. These methods should be used with extreme caution if at all.  As CRM forms get customized, updates depreciate code, and data changes JavaScript can break and throw errors.  If code is difficult to read it is difficult to debug and fix.  The following three functions all contain the same logic, but is written differently.

The first function has all the logic written in the same line.  Although this is a perfectly valid way to build a library, it is difficult to read at a glance.  It can also be very difficult to debug in Internet Explorer as long functions can easily become confusing.

The second function has been minified using the tool found at http://www.jsmini.com/.  Minification is often used when a developer is attempting to make their code difficult to reverse engineer or make their library as small as possible.  Notice the letter ‘a’ is used to represent more than one item in the line of logic.  This makes resolving issues in small libraries extremely difficult and nearly impossible in complex libraries.  Minification is not recommended in most CRM deployments.

The third function is written cleanly and is much easier to follow and debug.  An experienced developer can understand the intent of this function at a glance and can identify simple problems very quickly.  More complicated issues can be resolved in less time as well because this code is much easier to follow when debugging in Internet Explorer.  This can go a long way towards saving your organization money when issues arise.

java2

Use safe and efficient logic

Often times you will see examples of manipulating form controls on the internet or in technical documents.  Not all of these are safe or efficient.  It is important to remember that the processor cannot make the right decisions for your library.  It will only do what you tell it to do.

  • Only grab what you need when you need it

Here are two examples of how to set a field’s ReadOnly property.  When the OnSomeEvent function fires it will call two different versions of the DisableField function.  The first of which is extremely inefficient as it will grab all controls on the form, put them in a collection, and loop through all of them to perform an action on only one.  The second function is far more efficient.  It looks for the control by its logical name then makes sure it was found before carrying out the requested action.

codesnippet_JS_best_practices

  • Use comments in your code

Just because you understand what a certain piece of code does doesn’t mean the next person that sees your library will as well.  You may not even understand it several months down the road.  Conservative use of comments within your functions can be extremely useful when working in your libraries after a great deal of time has passed.  Always remember, however, that comments are still data within the JavaScript file.  Adding too many comments or ‘commenting out’ large portions of code instead of deleting them will bloat your library and can decrease performance on CRM forms.

Use non-blocking queries when retrieving CRM data

Oftentimes data required to provide useful information on the form is stored in other records throughout CRM.  It is important to understand why and when the data is being retrieved to maximize user experience throughout your CRM deployment.  Consider the following scenario:

Joe CRM wants to customize his account form to display a calculations of various values retrieved from the currently opened account’s sub accounts.  He wants these values to be calculated every time a user opens an account form to ensure that the data displayed is always up to date when a user views a record.

It is important to keep in mind that retrieving data to complete this requirement is not an instant process.  If the account being opened has a large number of sub accounts to retrieve and calculate from, the query could take several seconds to return its data.  A series of queries may also be required depending on what information Joe requires.  Furthermore, if the service being used to retrieve the data is heavily used the response can take longer.  Should Joe use a blocking (synchronous) query the user’s form will appear to lock up while the necessary information is being retrieved forcing the user to wait for the query to complete before being able to continue.  Joe should consider using a non-blocking (asynchronous) query to accomplish his task instead.  This will allow the user to work without waiting for the results to come back.  The query can run in the background the appropriate field(s) can be updated when the results are returned.

Several service endpoints are available to build queries against within CRM.  Each one has distinct advantages and disadvantages.  You can find information on service endpoints available for JavaScript queries here:

http://msdn.microsoft.com/en-us/library/hh771584.aspx#BKMK_DataAccessUsingJavaScript

Use read only, unique values when interacting with items on the CRM form

Objects on CRM forms such as fields, sections, and tabs all have several identifiers that can be used to target them with JavaScript.  You should take great care when deciding which identifier to use when building libraries.  Some values can change as CRM gets customized which will cause your JavaScript to break without warning.  Consider the following scenario:

Joe CRM’s account form has a custom section named Company in the form’s out of the box General tab.  Various functions in the account form’s JavaScript library show and hide the Company section when certain conditions are met.  Joe needs a function that can be called by other functions any time this section needs to be visible or hidden.  He writes the following function to accomplish the task.

java4

The method finds the general tab, then gets a list of all sections within that tab.  Then it investigates each section to see if the label equals ‘Company’.  If the section is found, the visibility property is toggled.

Although this function will still operate correctly, there are some flaws:

  • First, looping through all items is a waste of system resources.  Joe knows exactly which section he wants to manipulate.  He should grab that section directly to improve performance.
  • Second, grabbing a CRM form object by its label is extremely unsafe.   The label on a section equates to a display name.  Should the contents of the Company section change to something like sales data or company contacts the label on the section will likely change as well.  Once this happens the user will not see an error, but the showing and hiding of the section will appear to be broken.  In reality, the code is working exactly as it was designed, but the system it was designed for has evolved and failed to bring the business logic with it.

To properly resolve these issues, we should first investigate the Section Properties in the form’s Customizations area.  Double clicking the custom section will bring up the Section Properties.  The objects of importance here are the Name and Label values.

java5

Line 8 of Joe’s JavaScript function uses the section’s .getLabel() method to pull the Label value which is assigned on this screen.  This value is what appears on the form if the Show the label of this section on the Form option is checked.  The value Joe should be using is the Name property.  Although this value can still be modified during customization, it is far less likely to change than the label.  Here is a more efficient, and safer, way to write Joe’s function.

java6

This pattern is much safer than Joe’s original function in addition to being more efficient.  Take note of line 22.  This line grabs the section directly by its Name property instead of checking its more volatile Label property.

Some objects on CRM forms have identifying properties that cannot be changed during customization.  Fields, for example, have three primary properties that can be used to identify them using JavaScript.

  1. Logical Name
  2. Schema Name
  3. Display Name

Much like the label example with Joe’s hide section function, the display name is available but should never be used.  The Logical Name and Schema Name properties should be used instead.  The decision on which to use often depends on what you are doing.  The following image is taken from an out of the box CRM deployment and is looking at the fields for the Account form in the Default Solution.

java7

Notice the Name (logical name) and Schema Name columns.  The Logical Name should be identical to the Schema Name but in lower case.  Many times blogs, and even the CRM 2011 SDK for that matter, will mention using the schema name in methods like .getAttribute() or .getControl();  Either Schema Name or Logical Name is acceptable in this instance and they will both function in the same manner.  Both of these columns are defined when the field is created and cannot be modified through customization.

You have already seen throughout this chapter how to interact with a field using Xrm.Page.getAttribute (“logicalname”).  The parameter value (logicalname) is case sensitive and failure to use the attribute Logical Name may result in unexpected errors.  Commonly used development tools like Visual Studio cannot detect errors within string values which makes debugging casing related errors very difficult and time consuming.  It is for these reasons that an attribute’s Logical Name is the preferred parameter when authoring CRM JavaScript.

The CRM system ensures that attribute logical names are always lower case when an attribute is created where attribute schema name casing is not enforced.  By always using an attribute’s logical name, you can remove attribute name casing as point of failure in your code.  A notable exception to this rule is the requirement of Schema Name instead of Logical Name when querying against the CRM REST endpoint.

Learn more about SOAP and REST queries here:  http://msdn.microsoft.com/en-us/library/gg490659.aspx