Friday, December 23, 2016

Validation of Telephone Number using Javascript

function telephone_Onchange(fieldname) {
    var targetattribute = Xrm.Page.getAttribute(fieldname);
    var phonenumber = targetattribute.getValue();
    var targetcontrol = Xrm.Page.getControl(fieldname);
    if (phonenumber == null) {
        targetcontrol.clearNotification();
        return;
    }
    if (phonenumber.length == 0) {
        targetcontrol.clearNotification();
        return;
    }
    phonenumber = phonenumber.replace(/\+/g, "");
    phonenumber = phonenumber.replace(/\(/g, "");
    phonenumber = phonenumber.replace(/\)/g, "");
    phonenumber = phonenumber.replace(/\-/g, "");
    phonenumber = phonenumber.replace(/\s/g, "");
    phonenumber = phonenumber.replace(/\./g, "");
    if (isNaN(phonenumber) || phonenumber.length < 10 || phonenumber.length > 12) {
        targetcontrol.setNotification("Telephone number not validIt ");
        return;
    }
    targetcontrol.clearNotification();

}

Web API in MS CRM 2016

//Used to set Line of Business on create of Account record (Fetch LOB from the User Entity)
function onLoadSetLineOfBusiness(LineofBusiness) {
    var logInUser = Xrm.Page.context.getUserId();
    var retrieveRecordsReq = new XMLHttpRequest();
    var serverUrl = Xrm.Page.context.getClientUrl();
    // Adjust URL for differences between on premise and online
    if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); }

    //Web API Calls
    var req = new XMLHttpRequest();
    if (logInUser != null && logInUser != "") {
        req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/systemusers?$select=_new_lineofbusiness_value&$filter=systemuserid eq " + logInUser.replace('{', '').replace('}', '') + "", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");
        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 200) {
                    var LOBName = JSON.parse(this.response);
                    if (LOBName.value.length > 0) {
                        //to set the LookUp Value we have to use Formatted Value
                        if (LOBName.value[0]._new_lineofbusiness_value != null && LOBName.value[0]._new_lineofbusiness_value != "") {
                            var LOBvalue = new Array();
                            LOBvalue[0] = new Object();
                            LOBvalue[0].id = LOBName.value[0]._new_lineofbusiness_value;
                            LOBvalue[0].name = LOBName.value[0]['_new_lineofbusiness_value@OData.Community.Display.V1.FormattedValue'];
                            LOBvalue[0].entityType = "new_business";
                            Xrm.Page.getAttribute(LineofBusiness).setValue(LOBvalue);
                            Xrm.Page.getAttribute(LineofBusiness).setSubmitMode("always");
                        }
                    }
                }
                else {
                    alert(this.statusText);
                }
            }
        };
        req.send();
    }
}


Set the Default form in MS CRM

If we have more than one Form in an Entity and want to set a default form on Create/Update. Currently The below code will show if we are creating a New record then it will automatically redirect to Account-Create form

//Navigate to Account-Create Form onLoad
function NavigateToAccountCreateForm() {
    if (Xrm.Page.ui.getFormType() == 1) {
        var formLabelName = Xrm.Page.ui.formSelector.getCurrentItem().getLabel();
        if (formLabelName != "Account-Create") {
            var infIndex = null;
            Xrm.Page.ui.formSelector.items.forEach(function (item, index) {
                var itemLabelName = item.getLabel();
                if (itemLabelName == "Account-Create")
                { infIndex = index; }
            });

            if (infIndex != null) { Xrm.Page.ui.formSelector.items.get(infIndex).navigate(); }
            else { alert("Account-Create form not found. You cannot create new Account, Please contact your system administrator."); }
        }
    }

}

Another Method

function showDefaultForm() {
    //if the form is Create form
    if (Xrm.Page.ui.getFormType() == 1) {
        //check if the current form is Information Form
        if (Xrm.Page.ui.formSelector.getCurrentItem().getLabel() != "Information") {
            var items = Xrm.Page.ui.formSelector.items.get();
            for (var i in items) {
                var item = items[i];
                var itemId = item.getId();
                var itemLabel = item.getLabel()
                if (itemLabel == "Information") {
                    //navigate to the form
                    item.navigate();
                } //endif
            } //end for
        } //endif
    }
    //if the form is update form
    if (Xrm.Page.ui.getFormType() == 2 || Xrm.Page.ui.getFormType() == 4) {
        // variable to store the name of the form
        var lblForm;

        // get the value picklist field
        var relType = Xrm.Page.getAttribute("hsl_formtype").getValue();

        // switch statement to assign the form to the picklist value
        //change the switch statement based on the forms numbers and Formtype values
        switch (relType) {
            case 864630000:
                lblForm = "Information0";
                break;
            case 864630001:
                lblForm = "Information1";
                break;
            case null:
                lblForm = "Information2";
                break;
            default:
                lblForm = "Information";
        }
        //check if the current form is form need to be displayed based on the value
        if (Xrm.Page.ui.formSelector.getCurrentItem().getLabel() != lblForm) {
            var items = Xrm.Page.ui.formSelector.items.get();
            for (var i in items) {
                var item = items[i];
                var itemId = item.getId();
                var itemLabel = item.getLabel()

                if (itemLabel == lblForm) {
                    //navigate to the form
                    item.navigate();
                } //endif
            } //end for
        } //endif
    }//endif

} //end function

Wednesday, December 21, 2016

Microsoft Dynamics CRM Turbo Forms with Faster Rendering

Forms will load significantly faster and more efficiently.
The new renderer is based on previous generations and has the same functionality and behavior. However, there are some things that admins and developers need to do to ensure full compatibility when upgrading.

Each CRM form is held in an IFRAME but previously these weren’t retained in the browser which meant the entire IFRAME needed to be reloaded each time a similar record is opened.

IFRAMES are now retained throughout the user session. For example, once you’ve opened the first contact record in a session CRM will cache the frame enabling subsequent contacts to be opened without reloading this component.

CRM now handles common and custom scripts separately to achieve further performance gains.

Common scripts will always be cached and never need to be reloaded during this session.
Because caching is only retained per user session it means that the initial form rendering for each entity will take slightly longer after logging in but all subsequently forms for the same entity will load significantly quicker.

Custom scripts are now loaded in a separate IFRAME and are discarded when the user closes the form but because CRM now retains common scripts users will immediately enjoy faster form loads once this upgrade is applied.

Microsoft has made further changes to CRM’s form rendering which now handles more processes concurrently to shave off additional time each time a record is loaded compared to earlier versions.

In order to help catch unsupported customization's, we added a dialog that displays the issue when script errors occur so that they do not fail silently. If these symptoms occur, then it is likely there are unsupported customization's in the system.


There are 2 main changes that have been made: loading process of the form, and handling of cache.
In terms of loading process, we have parallelized as many operations as possible to eliminate time wasted because the browser is idle. We increased the content that’s cached, moved rendering processes partially to server-side, and optimized the initialization of controls.
Form load used to be a very linear process. Since the new form renderer is more parallelized, the rendering engine now constructs the form and XRM model first and binds the data whenever the server responds. The diagram below is a rough approximation in order to illustrate the differences between the 2 rendering engines and may not reflect the exact changes.


Customers should all make sure to test their organization in sandbox mode to preview before upgrade. This way, should any symptoms show up around forms not loading/script errors, you will be able to catch and fix it
before upgrade.
  • Any attempt to access DOM in the content iframe using JS, jQuery or other 3rd party libraries (document.getElementById() or jQuery selectors)
  • Creating a new HTML content in the parent window for persistent content (and assumed that the parent window was the main CRM iframe.
  • Window.load, parsing iframe/form URL
  • Attempting to use unsupported (non-XRM) APIs, especially undocumented ones that may have been shipped with CRM for internal usage only
  • Accessing window.parent() from a web resource that may assume for example there’s a variable set in the current window context.    
Fallback options
  • No action is needed by users or administrator as this is turned on by default.
  • The loading process for record forms is significantly better and faster since more content is cached. For more information on performance, see Microsoft’s note on form rendering engine.
  • Common and custom scripts are handled separately.
  • The engine has the same functionality as it is based on previous generations. It uses Form XML Schema and has full support for client scripting.
  • Access window.parent from a web source that has to do with a variable set.
  • Unsupported APIs, i.e., non-XRM.
  • Window.load or iframe/form.
  • Access DOM in content iframe using JQuery or JavaScript.
Examples of things that will break:
·         In case there is difficulty identifying the issue or a backup plan is needed post-upgrade, we have introduced an organizational-level fallback to temporarily allow usage of the legacy rendering engine. This will ensure compatibility at the cost of performance. Do not rely on this solution long term as the plan is to remove this option in the following release.
·         This setting can be found under Settings -> Administration -> System Settings -> General. Select “Yes” under “Use legacy form rendering” to enable this mode for all users.
·         If script errors are showing up, or if forms are not behaving as intended, this setting can be used to diagnose if the problem is specific to the new form rendering or not. If it is due to the new form rendering engine, then most likely there are some unsupported customization's.
Here are a few of the benefits of the new Form Rendering Engine:
  • No action is needed by users or administrator as this is turned on by default.
  • The loading process for record forms is significantly better and faster since more content is cached. For more information on performance, see Microsoft’s note on form rendering engine.
  • Common and custom scripts are handled separately.
  • The engine has the same functionality as it is based on previous generations. It uses Form XML Schema and has full support for client scripting.
The tricky thing for users and administrators has to do with unsupported customization's or direct DOM manipulations which will possibly fail and need to be re-engineered. The following are examples of when this might occur:
  • Access window.parent from a web source that has to do with a variable set.
  • Unsupported APIs, i.e., non-XRM.
  • Window.load or iframe/form.
  • Access DOM in content iframe using JQuery or JavaScript.

When using JavaScript code in Microsoft Dynamics CRM, it is possible that some code will stop working or cause an error when you upgrade. The Microsoft Dynamics CRM Custom Code Validation Tool helps identify potential problems so that a developer can fix them.
Please run this tool on your CRM instance to help identify potential issues with custom JavaScript in JavaScript libraries and HTML web resources. It will detect issues in the custom web resources that will no longer work after the upgrade is completed.
The most common issues that this tool targets are:
  • Common DOM manipulations
  • CRM 2013 Deprecated APIs
Running this tool before upgrade will enable you to identify issues and fix them prior to your scheduled upgrade so that your upgrade process can run smoothly. Microsoft Dynamics CRM 2015 Custom Code Validation Tool

Wednesday, June 8, 2016

Error: 400: Bad Request in MS CRM

Error: 400: Bad Request: Error processing request stream. The property name 'field_Name' specified for type 

'Microsoft.Crm.Sdk.Data.Services.field_Name' is not valid.

I had forgotten that I needed to specify the Schema name of the attribute and this is Case Sensitive. Once I had the case correct everything worked 

well again.

Error processing request stream. The property name 'new_Email' specified for type 'Microsoft.Crm.Sdk.Data.Services.Incident' is not valid.
check the field name in this. Check the Letters CASE

Validate Business Process Flow using Javascript

function AddStageHandlers() {
    Xrm.Page.data.process.addOnStageChange(StageChangedHandler);
}

function StageChangedHandler() {
    var activeStage = Xrm.Page.data.process.getActiveStage();
    var stageid = Xrm.Page.getAttribute("stageid").getValue();
    var peocessid = Xrm.Page.getAttribute("processid").getValue();
    var stageName = activeStage.getName();
    if (stageName == "BPF Stage Name") {
        if (Xrm.Page.getAttribute("optionsetattributename").getText() == "Yes") {
            if (Xrm.Page.getAttribute("attributename").getValue() == null) {
                //Previous stage ID
                Xrm.Page.data.process.movePrevious(function () { Xrm.Page.data.process.setActiveStage('stageid'); alert("All fields are Mandatory"); });
            }
            else {
                //Next stage ID
                Xrm.Page.data.process.moveNext(function () { Xrm.Page.data.process.setActiveStage('stageid'); alert("All fields are Mandatory"); });
            }
        }

        else {
            //Next stage ID
            Xrm.Page.data.process.moveNext(function () { Xrm.Page.data.process.setActiveStage('stageid'); alert("All fields are Mandatory"); });
        }
    };
}

How to set Optionset Valueby Text

function setOptionSetValueByText() {
    var optionText = Xrm.Page.getAttribute("statuscode").getText();
    var options = Xrm.Page.getAttribute("new_status").getOptions();
    for (i = 0; i < options.length; i++) {
        if (options[i].text == optionText) {
            Xrm.Page.getAttribute("new_status").setValue(options[i].value);
        }
    }
}

Fetch Child records in MS CRM

function fetchChildRecord() {
    var GUIDvalue = Xrm.Page.data.entity.getId();
    if (GUIDvalue != null) {
        //alert(GUIDvalue);
        var childRec = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
                            "<entity name='contact'>" +
                            " <attribute name='fullname' />" +
                            " <attribute name='parentcustomerid' />" +
                            " <attribute name='telephone1' />" +
                            " <order attribute='fullname' descending='false' />" +
                            " <filter type='and'>" +
                            " <condition attribute='parentcustomerid' operator='eq'  value='" + GUIDvalue + "' />" +
                            " </filter>" +
                            "</entity>" +
                            "</fetch> ";

        var childRecords = XrmServiceToolkit.Soap.Fetch(childRec);
        if (childRecords.length > 0) {
            if (childRecords[0].attributes.status != undefined) {
                var StatusValue = childRecords[0].attributes.fullname.value;
                alert(childRecords[0].attributes.fullname.value);
                //return StatusValue;
            }
        }
    }
}

//Have to add the XrmServiceToolkit.js file 
//links to download the file xrmservicetoolkit/xrmservicetoolkit 

Thursday, May 26, 2016

How to set the From and To Default values in Email in MS CRM

function RetrieveTOfromCASE() {
    var regardingObject = Xrm.Page.getAttribute("regardingobjectid");
    if (regardingObject.getValue() != null) {
        //SDK.REST.retrieveRecord(guid,entityname,select query,null,successcallback,errorcallback);
        SDK.REST.retrieveRecord(regardingObject.getValue()[0].id, "Incident", "Title,ContactId", null, successRetrieveEmail, errorHandler);
        
    }
}

function DefaultFROMandTO(GUID, NAME, LOGICALNAME) {
    //Set From Value
    if (Xrm.Page.ui.getFormType() == 1) {
        var lookupValue = new Array();
        lookupValue[0] = new Object();
        lookupValue[0].id = "GUID";
        lookupValue[0].name = "NAME(Contact/User/Queue)";
        lookupValue[0].entityType = "ENTITYNAME(Contact/User/Queue)";
        Xrm.Page.getAttribute('from').setValue(lookupValue);

        //Set To Value
        var lookupValue = new Array();
        lookupValue[0] = new Object();
        lookupValue[0].id = GUID;
        lookupValue[0].name = NAME;
        lookupValue[0].entityType = LOGICALNAME;
        Xrm.Page.getAttribute("to").setValue(lookupValue);
    }
}

var successRetrieveEmail = function (results) {
    DefaultTO(results.ContactId.Id, results.ContactId.Name, results.ContactId.LogicalName);
}

function errorHandler(error) {
}

//You need to add CRMSDK for this to work

Get Parent value in Child Record in MS CRM

function GetParentValue() {
//Fetch the case id.
//calling this function on Email form
    var regardingObject = Xrm.Page.getAttribute("regardingobjectid");
    if (regardingObject.getValue() != null) {
        //OData URI to get address information from parent account record
        var oDataURI = Xrm.Page.context.getClientUrl()
            + "/XRMServices/2011/OrganizationData.svc/"
            + "IncidentSet(guid'" + regardingObject.getValue()[0].id + "')"
            + "?$select=Title,ContactId";

        //Asynchronous XMLHttpRequest to retrieve account record
        var req = new XMLHttpRequest();
        req.open("GET", encodeURI(oDataURI), true);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.onreadystatechange = function () {
            debugger;
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null; //avoids memory leaks
                if (this.status == 200) {
                    //parse the response string as a JSON object into the successCallback method.
                    //successCallback(JSON.parse(this.responseText).d);
                    //Directly show the alert and assign accordingly to other values
                    alert(JSON.parse(JSON.parse(this.responseText).d.Title));
                }
                else {
                    errorCallback(CaseID);
                }
            }
        };
        req.send();
    }
}

//Call the GetParentValue method on OnLoad.