2

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!

Sergii Gorkun
  • 216
  • 2
  • 15
  • Why not use OData? There are loads of code samples on the MSDN to help with that. – James Wood Mar 04 '13 at 08:38
  • I'd like to use Odata, but I can't remake code so much. This system is working for a long time and the customer insists to rewrite this code. They believe that the testing in this case does not take much time. – Sergii Gorkun Mar 04 '13 at 09:05
  • The problem isn't only selectSingleNode - ActiveXObject will also not work for non IE – ccellar Mar 05 '13 at 13:12
  • Thanks I know this fact, it must be another codу for chrome too. – Sergii Gorkun Mar 06 '13 at 09:28
  • @SergiiGorkun it might be helpful for you to show us the upstream code that is expected to have produced this. Also, can you debug into this call and expand the results of `xmlhttp.responseXML` and then post the XML it returns. – Mike_Matthews_II Mar 12 '13 at 20:51

3 Answers3

2

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

Peter
  • 7,792
  • 9
  • 63
  • 94
2

I was facing the similar issue and I resolved it by using below workaround.

var sFetchResult = xmlhttp.response;
var tempresultDoc = new ActiveXObject("Microsoft.XMLDOM");
tempresultDoc.async = false;
tempresultDoc.loadXML(sFetchResult);

// Now at this point we will have the XML file. Get the singleNode from the XML by using below code.

var resultDoc = new ActiveXObject("Microsoft.XMLDOM");
resultDoc.async = false;
resultDoc.loadXML(tempresultDoc.childNodes[0].selectSingleNode("//a:Entities").xml);

Regards, Krutika Suchak

0

If you're looking for a version that doesn't require JQuery, and one that parses the results, check this out. It not only wraps the FetchXML, but also parses the response XML into JavaScript objects for easy retrieval.

Daryl
  • 18,592
  • 9
  • 78
  • 145