Search code examples
javascriptdynamics-crm-2011crmfetchxml

How could I remake FetchUtil.js for CRM 2011 UR 12


I have to remake FetchUtil.js for using it in CRM 2011 UR 12. I'm not very good in javascript, so I need some help.

This is the native code

 var sFetchResult = xmlhttp.responseXML.selectSingleNode("//a:Entities").xml;
 var resultDoc = new ActiveXObject("Microsoft.XMLDOM");
 resultDoc.async = false;
 resultDoc.loadXML(sFetchResult);

It doesn't work even in IE now, because of .selectSingleNode("//a:Entities").xml I did it like this, but there is no xml field there.

sFetchResult = xmlhttp.responseXML.getElementsByTagName('a:Entities')[0].xml;
    var resultDoc = new ActiveXObject("Microsoft.XMLDOM");
    resultDoc.async = false;
    resultDoc.loadXML(sFetchResult);

Help me to remake this for IE and Chrome. Thanks a lot!


Solution

  • Here is my calling module (include as webresource)

    (function (module, undefined) {
    
        module.buildFetchRequest = function (fetch) {
            /// <summary>
            /// builds a properly formatted FetchXML request
            /// based on Paul Way's blog post "Execute Fetch from JavaScript in CRM 2011"
            /// http://blog.customereffective.com/blog/2011/05/execute-fetch-from-javascript-in-crm-2011.html
            /// </summary>
            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(fetch);
    
            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 request;
        };
    
        module.sendFetchQuery = function (fetchRequest, doneCallback, failCallback) {
            //path to CRM root
            var server = window.location.protocol + "//" + window.location.host;
    
            //full path to CRM organization service - you may need to modify this depending on your particular situation
            var path = server + "/XRMServices/2011/Organization.svc/web";
    
            $.ajax({
                type: "POST",
                dataType: 'xml',
                async: false,
                contentType: "text/xml; charset=utf-8",
                processData: false,
                url: path,
                data: fetchRequest,
                beforeSend: function (xhr) {
                    xhr.setRequestHeader(
                        "SOAPAction",
                        "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute"
                    ); //without the SOAPAction header, CRM will return a 500 error
                }
            }).done(doneCallback)
              .fail(failCallback);
    
        };
    
    }(window.xFetch = window.xFetch || {}));
    

    Usage (the parser requires jQuery ... I am doing most of my fetch calls in web resourced html pages so this isn't a problem) this works in IE and Chrome haven't checked firefox but I can't see why it wouldn't work.

       var fetchXml =
                    xFetch.buildFetchRequest("<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
                        "   <entity name='ENTITYNAME'>" +
                        "    <attribute name='ATTRIBUTE' />" +
                        "  </entity>" +
                        "</fetch>");
    
                var entityList = new Array();
    
                xFetch.sendFetchQuery(fetchXml,
                    function (fetchResponse) {
    
                        // chrome doesn't like the namespaces because of 
                        // selectSingleNode implementations (which make sense btw)
                        // I'll never understand why Microsoft have to pepper their xml 
                        // with namespace dross
                        $(fetchResponse).find("a\\:Entity, Entity").each(function () {
    
                            var entityData = {};
    
                            $(this).find("a\\:KeyValuePairOfstringanyType, KeyValuePairOfstringanyType").each(function () {
                                var xmlElement = $(this);
                                var key = xmlElement.find("b\\:key, key").text();
                                var value = xmlElement.find("b\\:value, value").text();
                                entityData[key] = value;
                            });
    
                            //inner loop
                            $(this).find("a\\:KeyValuePairOfstringstring, KeyValuePairOfstringstring").each(function () {
                                var xmlElement = $(this);
                                var key = xmlElement.find("b\\:key, key").text();
                                var value = xmlElement.find("b\\:value, value").text();
                                entityData[key] = value;
                            });
    
                            entityList.push(entityData);
                        });
    
                    }, function (jqXhr, textStatus, errorThrown) {
                        // if unsuccessful, generate an error alert message
                    });
    
    
                for (var i = 0; i < entityList.length; i++) {
    
                    if (entityList[i].ATTRIBUTE === "Yes" ){ 
                       // DO WHATEVER
                    }
                }
    

    I only needed attributes with KeyValuePairOfstringstring and KeyValuePairOfstringanyType but you could parse out any attribute with the right combination of selectors

    each item in retrieved