Wednesday, April 21, 2010

MSCRM 4.0: Hide Duplicate Titles of CRM Notes Field

There was a question on CRM Development Forum about how to hide one of the titles of CRM notes field. The requirement is to make it looks like something as below.

Before hiding:


After hiding the titles:


Here is the script that I came up.

(function hideNotesTitle() {
    var notesField = crmForm.all.notescontrol;
    if (!notesField) return;  // there is no notes field on current form

    var onReadyStateChange = function() {
        if (notesField.readyState === 'complete') {
            var notesDoc = notesField.contentWindow.document;
            var notesTable = notesDoc.getElementById("NotesTable");
            var notesTableBody = notesTable.childNodes[1];

            for (var i = 0, len = notesTableBody.childNodes.length; i < len; i++) {
                var row = notesTableBody.childNodes[i];
                if (row.className == "noteHeader" && !row.oId) {
           = "none";

            notesField.detachEvent('onreadystatechange', onReadyStateChange);

    notesField.attachEvent('onreadystatechange', onReadyStateChange);

To use the function, you simply copy the code to your CRM form's OnLoad event.

Hope this snippet gives you some idea about how to work with CRM notes field if you ever need to do something similar.


Sunday, April 18, 2010

MSCRM 4.0: Get CRM Report's ID by its Name

There has been a question on CRM Development Forum about how to get a CRM report's ID by its name. Here is the script that I came up using CRM Web Service Toolkit.
* Get a CRM report's ID by its name.
* @author Daniel Cai,
* Parameters:
* @param reportName: The CRM Report's name. 
getReportId = function(reportName)
    var fetchXml = [
        "<fetch mapping='logical'>",
           "<entity name='report'>",
           "<attribute name='reportid' />",
              "<condition attribute='name' operator='eq' value='", reportName, "' />",

    var result = CrmServiceToolkit.Fetch(fetchXml);
    if (result === null) {
        throw new Error("Report " + reportName + " cannot be found. "); // This should never happen if the report exists, but you should handle the exception just in case.

    return result[0].getValue("reportid");
To use the function, you simply call it with the report's name as the only parameter, e.g.
var reportId = getReportId("Quote"); // Get "Quote" report's GUID
You will have to make CRM Web Service Toolkit available on the form. You can either copy the toolkit's JS code to your form's OnLoad event, or use my another piece of script to load the toolkit from external file.

You may wonder why you ever need this function. The reason is, when you have a custom report built for a CRM entity, and you want to add a custom button on the entity form to launch the report instantly, in which case you will need to call CRM's RunReport() function, which takes report's GUID as the last parameter (sHelpId). When a custom report is downloaded/uploaded from one environment to another one, the report's ID would be different. If you won't want to hard-code your report's ID when you make call to CRM RunReport() function, it is when this function comes to rescue you.


Tuesday, April 06, 2010

MSCRM 4.0: Disable All Fields on a CRM Form Tab

There has been a question on CRM Development Forum about how to make all CRM fields read only on a CRM form tab. Here is the script that I just came up.
 * Disable all CRM fields on a CRM form's tab.
 * @author Daniel Cai,
 * Parameters:
 * @param tabIndex: The index number of the tab that you want to disable the 
 *                  CRM fields. It's a zero-based number. 
function disableTab(tabIndex) {
    var tab = document.all["tab" + tabIndex];

    for (var i = 0; i < tab.all.length; i++) {
        if (tab.all[i].Disabled !== undefined) {
            tab.all[i].Disabled = true;

To use the function, you simply call it with the tab's index number as the single parameter, e.g.
disableTab(2); // Disable all CRM fields on the third tab
Have fun.

Sunday, April 04, 2010

MSCRM 4.0: Watermark CRM DateTime Field

There are a lot of people in the world who prefer keyboard to mouse clicks when it comes to data input. Microsoft Dynamics CRM users usually like and appreciate the user controls that come with the CRM platform, such as the picklist, date picker, lookup, and etc. You may take all the credit as the magic developer for all the cool stuff that MSCRM team has delivered for us. But sooner or later, you may be asked by your CRM users, "Can we do this, can we do that? ", which is often something that MSCRM doesn't work the exact way out-of-box.

One of the features that your CRM users could possible request is, CRM datepicker is a nice control, it works very well, but sometime we as CRM users want to type in the date directly in the textbox instead of using mouse click to pick a date, which is way too slow to get the job done. But the problem is the CRM users often don't know in which format they are supposed to type in the date. You are asked if you can provide a visual hint to the user about the date format. Then as a professional CRM developer, you will quickly realize that, what your CRM users actually want is a watermark for the datepicker field in the CRM form, probably something like the following picture.
DateTime Watermark

You show the idea to your customer, in most cases they will like the idea, and think you are a genius that can read their mind. Then you come to the implementation, which I have done for you.
 * Setup watermark for CRM Date fields based on user's date time format settings.
 * @author Daniel Cai,
 * Parameters:
 * @param dateField: The datetime field that you want to apploy the watermark. 
 *                   If not provided, all Date fields in the form will be masked.
watermarkDateField = function(dateField) {
    var defaultColor = "#000000";
    var watermarkColor = "#9c9c9c";

    var clearWatermark = function(input) {
        // Clear the textbox only if the textbox contains the watermark text
        if (input.value === watermarkText) {
            input.value = "";
   = defaultColor;

    var updateWatermark = function(input) {
        if (input.value === "") {
            input.value = watermarkText;
   = watermarkColor;
        else {
   = defaultColor;

    var maskDateField = function(dateField)
        var inputBox = dateField.childNodes[1].childNodes[0].childNodes[0].childNodes[0];
        if (!!inputBox) {
            inputBox.attachEvent("onfocus", function() { clearWatermark(inputBox); });
            inputBox.attachEvent("onblur", function() { updateWatermark(inputBox); });
            inputBox.attachEvent("onchange", function() { updateWatermark(inputBox); });
            crmForm.attachEvent("onsave", function() { clearWatermark(inputBox); });

            inputBox.title = watermarkText;

    (function init() {
        if (dateField !== undefined) {
        else {
            var tables = document.getElementsByTagName("table");
            for (var i = 0; i < tables.length; i++) {
                if (tables[i].className === "ms-crm-DateTime") {

What you would do is, copy the above code to the onLoad event of your CRM entity form which you want to watermark your date fields, publish the entity change, and open an existing entity record or create a new one, whew, all the empty date fields should have been watermarked!

A couple of notes about the code before we go.
  • The dateField parameter of the function is optional. When provided, it will only watermark the provided date field. If dateField is not provided, it will watermark all date fields in the CRM form.
  • Using the same technique, you can easily add watermark to any CRM textbox fields if there is ever such need. 
Hope this helps.