Sunday, August 4, 2019

Guidelines to write good JavaScript code in Microsoft Dynamic CRM




Here is another blog post listing Most Common JavaScript methods for Dynamic 365 CRM


Naming your Web-Resource

Prefix_/EntityName/SpecificPurpose/[version].js

Few examples:
  • msdyn_/SalesInsightsConfig/Resources/Globalization.1025.js
  • new_/invoice/cancelAllContractNotificationOnRenewal.js
  • msdyn_/solutionlayers/static/js/main.js
  • new_/Quote/CreateDuplicateQuote.js

Note: It is important to consider having our own publisher where we can define our prefix to be used in all web-resource.


Commenting your Code

File comment to denote why, when and by whom its been created.

/********************** Source File Header **************************
Project Name: Clinic_ZZZZZ

Creation Date: 4th Feb 2018
Created By: vjCity \ Vipin Jaiswal
Last Modification Date: 27th Feb 2018
Last Modified By: vjCity \ Vipin Jaiswal
Version: 1.0.0.0
Purpose: Common JS Library
********************************************************************/

Going further in the blog you will notice how comments help us in understanding our code better.


Coding Style – Modular vs Object Oriented

When writing any helper class which is going to be used across all entities, I suggest going with Object Oriented way as we get a benefit of having our own namespace. There are two style of having object-oriented JavaScript code:
Explicit Namespace Declaration and using .(Dot) to have classification

// declare the default namespace
if (vjCity === undefined) {
    var vjCity = {};
}
/// The cached user role
var cachedUserRole = new Array();

////////////////////Global Values////////////////////
vjCity.ERRORNotification = "ERROR";
vjCity.WarningNotification = "WARNING";
vjCity.INFONotification = "INFO";

//*******************Dialogs*************************
vjCity.changePasswordDialogId = "C3E7C5CD-AEF7-4DE7-8483-FBDF494F1A04";
vjCity.submitBusinessIdeaDialogId = "1A7A07C8-6B21-48DB-8BB4-1199451086E3";

//*******************Workflows***********************
vjCity.SubmitCommitteeDecisionsWorkflowId = "E2D77408-4A98-43D0-8856-ABEDEB8537D4";
vjCity.MembershipRequest_WorkflowId = "6F327E10-B358-4332-85F4-18D08C16F076";
vjCity.MembershipRequest_TransferToSupportWorkflowId = "5FDAA058-2301-43E6-B82E-7300339529E9";


/*
* Retrieve data
* Id = Id of the record
* type = Entity logical name
* select = fields to be retrieved ex: "new_A,new_B"
* callback = callback function
* example how to call this function :
***********************************************
var obj = Xrm.Page.getAttribute("exkb_client").getValue();
    if (obj === null) return;
    getDataById(obj[0].id, 'exkb_client', 'exkb_clientId, exkb_ClientContact', function(o)
    {
        if(!!o)
            Xrm.Page.getAttribute("customerid").setValue([{id: o.exkb_ClientContact.Id, name:o.exkb_ClientContact.Name, entityType:'contact'}]);
    });
***********************************************
*/
vjCity.getDataById = function (id, type, select, callback) {
    var serverUrl = Xrm.Page.context.getClientUrl();
    var oDataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/" + type + "Set(guid'" + id + "')?$select=" + select;
    var req = new XMLHttpRequest();
    req.open("GET", oDataSelect, false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
    req.onreadystatechange = function () {
        if (req.readyState === 4) {
            if (req.status === 200) {
                callback(JSON.parse(req.responseText).d);
            }
        }
    };
    req.send();

};


All Code within curly bracket ( { )

// declare the default namespace
if (vjCity === undefined)
{
  var vjCity =
  {
    ////////////////////Global Values////////////////////
    ERRORNotification = "ERROR";
    WarningNotification = "WARNING";
    INFONotification = "INFO";

    //*******************Dialogs*************************
    changePasswordDialogId = "C3E7C5CD-AEF7-4DE7-8483-FBDF494F1A04";
    submitBusinessIdeaDialogId = "1A7A07C8-6B21-48DB-8BB4-1199451086E3";

    //*******************Workflows***********************
    SubmitCommitteeDecisionsWorkflowId = "E2D77408-4A98-43D0-8856-ABEDEB8537D4";
    MembershipRequest_WorkflowId = "6F327E10-B358-4332-85F4-18D08C16F076";
    MembershipRequest_TransferToSupportWorkflowId = "5FDAA058-2301-43E6-B82E-7300339529E9";


    /*
    * Retrieve data
    * Id = Id of the record
    * type = Entity logical name
    * select = fields to be retrieved ex: "new_A,new_B"
    * callback = callback function
    * example how to call this function :
    ***********************************************
    var obj = Xrm.Page.getAttribute("exkb_client").getValue();
        if (obj === null) return;
        getDataById(obj[0].id, 'exkb_client', 'exkb_clientId, exkb_ClientContact', function(o)
        {
            if(!!o)
                Xrm.Page.getAttribute("customerid").setValue([{id: o.exkb_ClientContact.Id, name:o.exkb_ClientContact.Name, entityType:'contact'}]);
        });
    ***********************************************
    */
    getDataById = function (id, type, select, callback) {
        var serverUrl = Xrm.Page.context.getClientUrl();
        var oDataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/" + type + "Set(guid'" + id + "')?$select=" + select;
        var req = new XMLHttpRequest();
        req.open("GET", oDataSelect, false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
        req.onreadystatechange = function () {
            if (req.readyState === 4) {
                if (req.status === 200) {
                    callback(JSON.parse(req.responseText).d);
                }
            }
        };
        req.send();
    };
  };
}

Modular Approach to JavaScript

This is most straight forward way of coding and we can use this style when we are writing entity specific code and we just need declaration of methods.

An Example:

///
/*
Date created : 10 Jan 2018
Name : Vipin Jaiswal
Last updated : 13 Feb 2018
Purpose : JS Library for Applicant(Contact) Entity
*/


//****************** Global Value ******************************
var entityName = "contact";
var recordId = Xrm.Page.data.entity.getId();

//*************** Form Methods Start ****************************

function form_OnLoad()
{
    SetDocumentFrame("IFRAME_documents");
    CheckMembershipExpiry();
    CheckEstablishment();
    var val = Xrm.Page.getAttribute("address1_postofficebox").getValue();
    Xrm.Page.getAttribute("address1_postofficebox").setValue(ValidatePOBox(val));
}

function form_OnSave()
{

}

//************ Ribbon Methods ***********************************
function changePasswordCallDialog()
{
    //Call the change password dialog
    Alert.showDialogProcess(changePasswordDialogId, entityName, recordId);
}
function bulkCreateCommitteeSessions()
{
    // Call the bulk create committee sessions
    Alert.showDialogProcess(bulkCreateCommitteeInstances, entityName, recordId);
}

//************* On Change Methods *************************
function EmploymentStatusOnChange() {
    CheckEstablishment();
}
function EmariteIdOnChange() {
    ValidateEmiratesId(Xrm.Page.getAttribute("kfexc_emiratesid").getValue());
}
function PassportExpiryDateOnChange() {
    var passportExprity = Xrm.Page.getAttribute("kfexc_passportexpirydate").getValue();
    if ((passportExprity !== null || passportExprity !== undefined) && vjCity.dateIsLater(Date.now(), passportExprity)) {
        vjCity.showFormNotification("Passport is Expired", vjCity.WarningNotification, "1");
    }
    else
        vjCity.clearFormNotification("1");
}

function BirthdateOnChange() {
    var birthdate = Xrm.Page.getAttribute("birthdate").getValue();
    if ((birthdate !== null || birthdate !== undefined) && vjCity.dateIsLater(birthdate, Date.now())) {
        vjCity.showFormNotification("Birth Date is in the future", vjCity.WarningNotification, "3");
    }
    else
        vjCity.clearFormNotification("3");
}
function MobileNumberOnChange() {
    var mobNumber = Xrm.Page.getAttribute("mobilephone").getValue();
}
function HomeNumberOnChange() {
    var Number = Xrm.Page.getAttribute("address1_telephone1").getValue();
    vjCity.ValidateMobileNumber(Number, "address1_telephone1");
}


//
//*************** Business Validation Methods **************

function ValidateEmiratesId(txt) {
    if (txt === "")
        return;
    var patt = new RegExp("^[0-9]{15}$");
    var res = patt.test(txt);

    if (!res || !txt.startsWith("784")) {
        vjCity.showFieldNotificiation("kfexc_emiratesid", "Emirates Id format is invalid");
    }
    else {
        vjCity.clearFieldNotification("kfexc_emiratesid");
        var a = "";
        for (var i = 0; i < txt.length ; i++) {
            switch (i) {
                case 2:
                    a = a + txt[i] + "-";
                    break;
                case 6:
                    a = a + txt[i] + "-";
                    break;
                case 13:
                    a = a + txt[i] + "-";
                    break;
                default:
                    a = a + txt[i];
            }
        }
        Xrm.Page.getAttribute("kfexc_emiratesid").setValue(a);
    }
}

function ValidatePOBox(val)
{
    if (val !== undefined && val != null)
        return val.replace("-", "");
    return "";
}


I hope there are better approach to have perfect coding style, please do let me know if you came across any in comments.

Thanks,
Vipin Jaiswal
vipinjaiswal12@gmail.com


4 comments:

Unknown said...

Nice Article

Unknown said...

Thanks for the article. It helps a lot.

Anonymous said...

Thanks for the information. Really liked it

invokker said...

Great article! Agreed on lots of points. Further, I’d like to add that you can get the Top CRM Software India-software recommendation at Technology Counter(A software and tech recommendation platform).