Quantcast
Channel: CRM 2011 – MS CRM, .NET Hints
Viewing all articles
Browse latest Browse all 7

Synchronously/Asynchronously Retrieve Fetch Data from CRM 2011 Using JavaScript

$
0
0

There are several ways that we can get CRM data into form asynchronously. CRM 2011 has inbuilt support to communicate with server using OData endpoints. One other most famous way to get the data from the CRM server is fetch XML. So here is a nice way to access server with FetchXML + JavaScript.

Let say you want to get the total estimated revenues of the all the opportunities that have probability over 75% of the Account, when you open an Account and populate that estimated revenue in a text field.

First you need to create jScript web resourse Called FetchUtil, paste following code into it. (You can find several versions of this FetchUtil tool in the google but this one will give results as array of objects which will be easier to handle than the result XML in the client side with the JavaScript. Actually it’s a combination of several approaches into one utility.)

var XMLHTTPSUCCESS = 200;
var XMLHTTPREADY = 4;

function FetchUtil(sOrg, sServer) {
    this.org = sOrg;
    this.server = sServer;

    if (sOrg == null) {
        if (typeof (ORG_UNIQUE_NAME) != "undefined") {
            this.org = ORG_UNIQUE_NAME;
        }
    }

    if (sServer == null) {
        this.server = window.location.protocol + "//" + window.location.host;
    }
}

FetchUtil.prototype._ExecuteRequest = function (sXml, sMessage, fInternalCallback, fUserCallback) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("POST", this.server + "/XRMServices/2011/Organization.svc/web", (fUserCallback != null));
    xmlhttp.setRequestHeader("Accept", "application/xml, text/xml, */*");
    xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");

    if (fUserCallback != null) {
        //asynchronous: register callback function, then send the request. 
        var crmServiceObject = this;
        xmlhttp.onreadystatechange = function () { fInternalCallback.call(crmServiceObject, xmlhttp, fUserCallback) };
        xmlhttp.send(sXml);
    }
    else {
        //synchronous: send request, then call the callback function directly 
        xmlhttp.send(sXml);
        return fInternalCallback.call(this, xmlhttp, null);
    }
}

FetchUtil.prototype._HandleErrors = function (xmlhttp) {
    /// <summary>(private) Handles xmlhttp errors</summary> 
    if (xmlhttp.status != XMLHTTPSUCCESS) {
        var sError = "Error: " + xmlhttp.responseText + " " + xmlhttp.statusText;
        alert(sError);
        return true;
    } else {
        return false;
    }
}

FetchUtil.prototype.Fetch = function (sFetchXml, fCallback) {
    /// <summary>Execute a FetchXml request. (result is the response XML)</summary> 
    /// <param name="sFetchXml">fetchxml string</param> 
    /// <param name="fCallback" optional="true" type="function">(Optional) Async callback function if specified. If left null, function is synchronous </param>


    var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
    request += "<s:Body>";

    request += '<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services">' +
                '<request i:type="b:RetrieveMultipleRequest" ' +
                ' xmlns:b="http://schemas.microsoft.com/xrm/2011/Contracts" ' +
                ' xmlns:i="http://www.w3.org/2001/XMLSchema-instance">' +
                '<b:Parameters xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic">' +
                '<b:KeyValuePairOfstringanyType>' +
                '<c:key>Query</c:key>' +
                '<c:value i:type="b:FetchExpression">' +
                '<b:Query>';

                    request += CrmEncodeDecode.CrmXmlEncode(sFetchXml);

                    request += '</b:Query>' +
                '</c:value>' +
                '</b:KeyValuePairOfstringanyType>' +
                '</b:Parameters>' +
                '<b:RequestId i:nil="true"/>' +
                '<b:RequestName>RetrieveMultiple</b:RequestName>' +
                '</request>' +
                '</Execute>';

                    request += '</s:Body></s:Envelope>';

    return this._ExecuteRequest(request, "Fetch", this._FetchCallback, fCallback);
}

FetchUtil.prototype._FetchCallback = function (xmlhttp, callback) {
    ///<summary>(private) Fetch message callback.</summary>
    //xmlhttp must be completed
    if (xmlhttp.readyState != XMLHTTPREADY) {
        return;
    }

    //check for server errors
    if (this._HandleErrors(xmlhttp)) {
        return;
    }

    var sFetchResult = xmlhttp.responseXML.selectSingleNode("//a:Entities").xml;

    var resultDoc = new ActiveXObject("Microsoft.XMLDOM");
    resultDoc.async = false;
    resultDoc.loadXML(sFetchResult);

    //parse result xml into array of jsDynamicEntity objects
    var results = new Array(resultDoc.firstChild.childNodes.length);
    for (var i = 0; i < resultDoc.firstChild.childNodes.length; i++) {
        var oResultNode = resultDoc.firstChild.childNodes[i];
        var jDE = new jsDynamicEntity();
        var obj = new Object();

        for (var j = 0; j < oResultNode.childNodes.length; j++) {
            switch (oResultNode.childNodes[j].baseName) {
                case "Attributes":
                    var attr = oResultNode.childNodes[j];

                    for (var k = 0; k < attr.childNodes.length; k++) {

                        // Establish the Key for the Attribute
                        var sKey = attr.childNodes[k].firstChild.text;
                        var sType = "";

                        // Determine the Type of Attribute value we should expect
                        for (var l = 0; l < attr.childNodes[k].childNodes[1].attributes.length; l++) {
                            if (attr.childNodes[k].childNodes[1].attributes[l].baseName == "type") {
                                sType = attr.childNodes[k].childNodes[1].attributes[l].text;
                            }
                        }

                        switch (sType) {
                            case "a:OptionSetValue":
                                var entOSV = new jsOptionSetValue();
                                entOSV.type = sType;
                                entOSV.value = attr.childNodes[k].childNodes[1].text;
                                obj[sKey] = entOSV;
                                break;

                            case "a:EntityReference":
                                var entRef = new jsEntityReference();
                                entRef.type = sType;
                                entRef.guid = attr.childNodes[k].childNodes[1].childNodes[0].text;
                                entRef.logicalName = attr.childNodes[k].childNodes[1].childNodes[1].text;
                                entRef.name = attr.childNodes[k].childNodes[1].childNodes[2].text;
                                obj[sKey] = entRef;
                                break;

                            default:
                                var entCV = new jsCrmValue();
                                entCV.type = sType;
                                entCV.value = attr.childNodes[k].childNodes[1].text;
                                obj[sKey] = entCV;

                                break;
                        }

                    }
                    jDE.attributes = obj;
                    break;

                case "Id":
                    jDE.guid = oResultNode.childNodes[j].text;
                    break;

                case "LogicalName":
                    jDE.logicalName = oResultNode.childNodes[j].text;
                    break;

                case "FormattedValues":
                    var foVal = oResultNode.childNodes[j];

                    for (var k = 0; k < foVal.childNodes.length; k++) {
                        // Establish the Key, we are going to fill in the formatted value of the already found attribute
                        var sKey = foVal.childNodes[k].firstChild.text;

                        jDE.attributes[sKey].formattedValue = foVal.childNodes[k].childNodes[1].text;


                    }
                    break;
            }

        }

        results[i] = jDE;
    }

    //return entities
    if (callback != null)
        callback(results);
    else
        return results;

}


function jsDynamicEntity(gID, sLogicalName) {
    this.guid = gID;
    this.logicalName = sLogicalName;
    this.attributes = new Object();
}

function jsCrmValue(sType, sValue) {
    this.type = sType;
    this.value = sValue;
}
function jsEntityReference(gID, sLogicalName, sName) {
    this.guid = gID;
    this.logicalName = sLogicalName;
    this.name = sName;
    this.type = "EntityReference";
}
function jsOptionSetValue(iValue, sFormattedValue) {
    this.value = iValue;
    this.formattedValue = sFormattedValue;
    this.type = "OptionSetValue";
}

Create organisation service using FetchUtil, add the following lines into your code. This will create organisation service for your CRM instance.

var serverUrl = Xrm.Page.context.getServerUrl();

var organizationName = Xrm.Page.context.getOrgUniqueName();

var oService = new FetchUtil(organizationName, serverUrl);

Create JavaScript method which will be called in the form load event of the account entity. It should then call the fetch utility service with Fetch XML. You can create relevant Fetch XML using advance find and then download the XML into your hard drive. Make sure to override filter value with the Current Account id before execute the Fetch XML.

<filter type='and'> " 

<condition attribute='accountid' operator='eq' uitype='account' value='" + Xrm.Page.data.entity.getId() + "' /> " 

</filter> " 

Here how you can call the FetchUtility fetch method synchronously.

var estimatedRevenueslResults = new Array(); 

estimatedRevenueslResults = oService.Fetch(getEstimatedRevenuesFetch); 

If you want to execute your code asynchronously you can use FetchUtil as follows.

var estimatedRevenueslResults = new Array(); 

oService.Fetch(getEstimatedRevenuesFetch,callbackfunction); 

function callbackfunction(estimatedRevenueslResults){ } 

Once the execution is finish it will call your call back function(callbackfunction) with the array of results.

So now you have the array of results and it’s easy to iterate through your result set and calculate estimated revenue.

if (estimatedRevenueslResults != null && estimatedRevenueslResults.length > 0) { 

   var totalEstimatedRevenue; 

   for (var key in estimatedRevenueslResults) { 

          if (estimatedRevenueslResults[key].attributes["estimatedvalue"] != undefined && estimatedRevenueslResults[key].attributes["estimatedvalue"].value != undefined) { 

         totalEstimatedRevenue += parseFloat(estimatedRevenueslResults[key].attributes["estimatedvalue"].value); 

          } 

    } 

/* populate field with the calculated totalEstimatedRevenue */ 

}

Viewing all articles
Browse latest Browse all 7

Latest Images

Trending Articles





Latest Images