- Avoid unsupported code
- Keep it simple
- Use safe and efficient logic
- Use non-block queries
- Use read-only, unique values
Avoid unsupported code
- .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.
- 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
- Make sure your libraries are readable
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.
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.
- Use comments in your code
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.
Use read only, unique values when interacting with items on the CRM form
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.
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.
- Logical Name
- Schema Name
- 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.
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.
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