Actually I have an issue with javascript. I find no solution for this problem yet.
Maybe someone of you could give me a hint.
I have a created a function, which is called by a button click.in SharePoint 2010.
The function should collect all selected / checked documents from a document library and write them into a separate box, I created. To get all selected documents works fine. But in SharePoint I have to load each element individually for details with an asynchronous request. Here comes my problem:
If I select more than one document, the variable "item" will be overwritten because of the "for" loop. In my asynchronous request success function, I use now the variable "item" again to get the details of it. So I always get the data of the last item of my selection.
Is there a way to avoid this?
Thanks for any help.
Here is my code:
function ApproveDocuments() {
var ClientContext = SP.ClientContext.get_current();
var LibraryID = SP.ListOperation.Selection.getSelectedList();
var Library = ClientContext.get_web().get_lists().getById(LibraryID); //Gets the current Library
var SelectedDocuments = SP.ListOperation.Selection.getSelectedItems(ClientContext);
for (var currentItem in SelectedDocuments) {
var item = Library.getItemById(SelectedDocuments[currentItem].id);
ClientContext.load(item, 'FileLeafRef');
ClientContext.executeQueryAsync(Function.createDelegate(this, function () {
var newElementHtml = '<div style="float:left;padding:3px;width:50px;"></div>';
newElementHtml += '<div style="float:left;padding:3px;">' + item.get_item('FileLeafRef') + '</div>';
newElementHtml += '<div style="clear:both;"></div>';
jQuery("#grol1855InfoDivData").append(newElementHtml);
}), Function.createDelegate(this, this.onLoadItemFailure));
}}
I would refactor this a bit so that you don't make an http request every time you iterate through the loop, which should also solve your over-write problem. I also declared the variables outside of the loops and make it point to the new version each iteration.
function ApproveDocuments() {
var ClientContext = SP.ClientContext.get_current();
var LibraryID = SP.ListOperation.Selection.getSelectedList();
var Library = ClientContext.get_web().get_lists().getByID(LibraryID); //Gets the current Library
var SelectedDocuments = SP.ListOperation.Selection.getSelectedItems(ClientContext);
var fileItems = [], item;
for (var currentItem in SelectedDocuments) {
item = Library.getItemById(SelectedDocuments[currentItem].id);
fileItems.push(item);
ClientContext.load(item, 'FileLeafRef');
}
ClientContext.executeQueryAsync(Function.createDelegate(this, function() {
var newElementHtml;
for (var i = 0; i < fileItems.length; i++) {
newElementHtml = '<div style="float:left;padding:3px;width:50px;"></div>';
newElementHtml += '<div style="float:left;padding:3px;">' + fileItems[i].get_item('FileLeafRef') + '</div>';
newElementHtml += '<div style="clear:both;"></div>';
jQuery("#grol1855InfoDivData").append(newElementHtml);
}
}), Function.createDelegate(this, this.onLoadItemFailure));
}
I would also really advise against writing new solutions that call any of the SOAP services or anything in _vti_bin for that matter; it's just a matter of time before those go away and your stuff won't work.
I have also tried ClientContext.executeQueryAsync in a loop but have never gotten it to work for similar reasons. I've worked around this before by using Ajax to call the SharePoint lists.asmx web service. For example:
var targetUrl = "/_vti_bin/lists.asmx";
var listName = "Shared Documents";
for (var currentItem in SelectedDocuments) {
var currentItemId = SelectedDocuments[currentItem].id;
var soapEnvArray = [];
soapEnvArray.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
soapEnvArray.push("<soap:Envelope ");
soapEnvArray.push("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">");
soapEnvArray.push("<soap:Body><GetListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><listName>" + listName + "</listName>");
soapEnvArray.push("<viewName></viewName>");
soapEnvArray.push("<query>");
soapEnvArray.push("<Where>");
soapEnvArray.push("<Eq>");
soapEnvArray.push("<FieldRef Name=\"ID\"></FieldRef>");
soapEnvArray.push("<Value Type=\"Counter\">" + currentItemId + "</Value>");
soapEnvArray.push("</Eq>");
soapEnvArray.push("</Where>");
soapEnvArray.push("</query>");
soapEnvArray.push("<viewFields>");
soapEnvArray.push("</viewFields>");
soapEnvArray.push("<rowLimit>2000</rowLimit><queryOptions><QueryOptions xmlns=\"\">");
soapEnvArray.push("<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>");
soapEnvArray.push("<ViewAttributes Scope = \"RecursiveAll\"/>");
soapEnvArray.push("</QueryOptions></queryOptions>");
soapEnvArray.push("</GetListItems></soap:Body></soap:Envelope>");
var soapEnv = soapEnvArray.join("");
$.ajax({
cache: false,
url: targetUrl,
type: "POST",
dataType: "xml",
data: soapEnv,
contentType: "text/xml; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetListItems");
},
complete: function (msg) {
if (msg.status == 200) {
var totalTaskCount = $(msg.responseXML).find("z\\:row, row").length;
$(msg.responseXML).find("z\\:row, row").each(function () {
console.log(currentItemId + ": " + $(this).attr("ows_Title"));
});
} else {
//Failure
var errorCode = $(msg.responseXML).find("errorcode").text();
var errorString = $(msg.responseXML).find("errorstring").text();
if (errorString.length === 0) {
errorString = $(msg.responseXML).find("faultstring").text();
}
errorString = errorString.replace(/(\r\n|\n|\r)/gm, "");
}
}
});
}
To make SharePoint Ajax requests easier, I would recommend picking up a copy of SharePoint CAML Query Helper for 2007, 2010, and 2013. Also, although I have never used it, you may want to consider trying the SPServices jQuery Library for SharePoint to simplify the task.
Related
How to Send Ajax Request in specific time and only that particular event
I m User Time Interval But it’s not Working.
i want get data in request 1 for use in request 2 but it get null data in request 2
setInterval()
it's not Working for me.
I want To send Request 2 After the some time of Request 1
Request 1:-
$(document).on("change", ".supplyItem", function (event) {
var id = $(this).attr("data-id");
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospital = $("#hospital").val();
var physician = $("#physician").val();
var category = $("#category").val();
var manufacturer = $("#manufacturer").val();
var project = $("#project").val();
if (hospital != "" && physician != "" && category != "" && manufacturer != "" && project != "") {
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getitemfile')}}",
data: {
supplyItem: supplyItem,
hospital: hospital,
project: project,
},
success: function (data) {
console.log(id);
if (data.status) {
var html_data = '';
var item = data.value;
console.log(item);
$('.hospitalPart[data-id=' + id + ']').val(item.hospitalNumber);
$('.mfgPartNumber[data-id=' + id + ']').val(item.mfgPartNumber);
// $('.mfgPartNumber[data-id='+id+']').text('something');
} else {
$('.hospitalPart[data-id=' + id + ']').val('');
$('.mfgPartNumber[data-id=' + id + ']').val('');
}
$('.quantity[data-id=' + id + ']').val('');
$('.purchaseType[data-id=' + id + ']').val('');
$('#serial-text' + id).val('');
$('#serial-drop' + id).val('');
$('#serial-drop' + id).empty();
}
});
}
});
Request 2:-
$(document).on('change', '.supplyItem', function (event) {
var timer, delay = 2000;
var id = $(this).attr("data-id");
var client = $("#hospital").val();
timer = setInterval(function(){
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospitalPart = $(".hospitalPart[data-id=" + id + "]").val();
var mfgPartNumber = $(".mfgPartNumber[data-id=" + id + "]").val();
alert(supplyItem);
alert(hospitalPart);
alert(mfgPartNumber);
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getdevicedata')}}",
data: {
supplyItem: supplyItem,
hospitalPart: hospitalPart,
mfgPartNumber: mfgPartNumber,
client: client,
},
success: function (data) {
if (data.status) {
var html_data = '';
var check = data.value;
if (check == 'True') {
html_data += "<option value=''>Purchase Type</option><option value='Bulk'>Bulk</option><option value='Consignment'>Consignment</option>";
$('.purchaseType[data-id=' + id + ']').html(html_data);
} else {
html_data += "<option value=''>Purchase Type</option><option value='Consignment'>Consignment</option>";
$('.purchaseType[data-id=' + id + ']').html(html_data);
}
}
}
});
}, delay);
clearInterval(timer);
});
You can move Request 2 into a function and this JS code will call the Request2 function after given interval of time (milliseconds), I have set it to 5 seconds for now.
setInterval(function () { Request2(); }, 5000);
function Request2(){
console.log("Request 2 called");
//add request 2 code here
}
jQuery's $.ajax method returns a promise, which is passed the result of the server-side call. You can chain these calls together so that you can build the result of multiple ajax calls. When you use it this way you do away with success callbacks as they are no longer necessary.
Applied to your code it might looks something like this:
$(document).on("change", ".supplyItem", function (event) {
var id = $(this).attr("data-id");
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospital = $("#hospital").val();
var physician = $("#physician").val();
var category = $("#category").val();
var manufacturer = $("#manufacturer").val();
var project = $("#project").val();
if (hospital != "" && physician != "" && category != "" && manufacturer != "" && project != "") {
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getitemfile')}}",
data: {
supplyItem: supplyItem,
hospital: hospital,
project: project,
})
.then(function(data1){
// process result of call1 and make call2
var item = data1.value;
return $.ajax({
url: "{{ URL::to('admin/repcasetracker/getdevicedata')}}",
data: {
supplyItem: supplyItem,
hospitalPart: value.hospitalPart, // note using result from 1 directly
mfgPartNumber: value.mfgPartNumber,
client: hospital
}
});
})
.then(function(data2){
// process result of call2
});
};
});
The point here is that you don't need to stash the result of call1 into some elements and re-read them before making call2, and trying to wait enough time before making call2. You just chain it all together with then.
Ok first though: Instead of using setInterval and then clearing the interval after it has run a single time, why not just use
setTimeout(function, delay);
Then personally I prefer to use XMLHttpRequest instead of Jquery AJAX, Jquery uses XMLHttpRequest at its base anyway,I just prefer it so I dont have to use Jquery, but if your already using Jquery in your site then it should be no more heavy. Here is a quick example of XMLHttpRequest so u can use it if you prefer.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'URL::to("admin/repcasetracker/getdevicedata")', true);
xhr.setRequestHeader("Content-Type", "application/json charset=utf8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// content is loaded...
if (xhr.responseText) {
//Some code to run after the server responds and it was successfull
}
}
};
xhr.send(JSON.stringify({test:'test'})); //This is the data you are handing to the server
Notice the use of xhr.responseText, JQuery uses the same variable and this is usually the response from the server. One sure way to know is use your browser's debugging engine (F12 on Chrome and Firefox, have no idea on other browsers) to inspect the variables, it is very easy to ascertain the correct variable to use.
And then one last thought: I see you are not declaring the content-type and not JSON.stringify'ing() your data when you send it to the server.
Best way to debug a situation like this is 'proccess of elimation' so find out if the server is receiving the data then if the server is proccessing the data correctly and then check if the server is sending the data correctly.
If you are using Nginx use the /var/log/nginx/error.log to see if it throws any errors ( tip: tail -f /var/log/nginx/error.log | Apache uses /var/log/http/error.log on most distros ) and if you are using .NET just debug it in Visual Studio.
And read up on the Jquery success event there is 2 more arguments that gets passed - String textStatus and jqXHR jqXHR
http://api.jquery.com/jquery.ajax/
So to summarize:
Make sure to declare the dataType: 'json'
Use the correct variable, should be responseText
when passing the server data and using 'json' make sure to JSON.stringify() it
And I don't quite see why you want to use setTimeout in the first place.
If you are simply waiting for the server to respond then using any type of delay will be a terrible idea, instead use the events that gets fired after the server responds.
So in Jquery that is success: function() {} and error: function() {}
and in XMLHttpRequest its the xhr.onreadystatechange = function () { }
On page load, the code below performs an api request and returns the result. I then have some code that on change of a selector updates one of the variables with the value of that selector and then re-requests the api using the function newsFeed();
My problem is the variable is not getting updated before the function has run.
How do you update a value before running a function containing ajax?
$(document).ready(function() {
var api = '//www.url.com'
var search = 'search?'
var orderBy = 'newest'
var url = api + search + orderBy
//API Call Setup
function newsFeed(data) {
$.ajax({
url: url,
success: function results(data) {
for (var i =0; i < data.response.total; i++) {
var content = '<li>' + data.response.results[i] + '</li>';
$('#news').append(content);
//end of for loop
};
}
});
}
newsFeed();
$("#selector").change(function(){
$('#news').empty(); //remove all child nodes
orderBy = $("#orderBy :selected").text();
newsFeed();
});
});
You're updating the orderBy variable, but then not updating the url with that. Move the declaration of url so it's in the same block as the AJAX call.
$(document).ready(function() {
var api = '//www.url.com';
var search = 'search?';
var orderBy = 'newest';
//API Call Setup
function newsFeed(data) {
var url = api + search + orderBy; // This line has been moved
$.ajax({
url: url,
success: function results(data) {
for (var i =0; i < data.response.total; i++) {
var content = '<li>' + data.response.results[i] + '</li>';
$('#news').append(content);
};
}
});
}
...
In your ajax call, you are requesting url: url
$.ajax({
url: url,
With url defined as
var url = api + search + orderBy
But var url doesn't get magically updated by changing one of the composing variable's value.
Once you've set url it's set (until you update it), so that would be the variable you'd need to update.
The quickest fix will be to just get rid of var url at all and use the ajax call like
$.ajax({
url: api + search + orderBy,
As baao said, your url variable inside newsFeed() doesn't get updated. I'd suggest passing variables as parameters to the newsFeed function.
$(document).ready(function() {
var api = '//www.url.com'
var search = 'search?'
//API Call Setup
function newsFeed(orderBy) {
// set url every time function is called
var url = api + search + orderBy
$.ajax({
url: url,
success: function results(data) {
for (var i =0; i < data.response.total; i++) {
var content = '<li>' + data.response.results[i] + '</li>';
$('#news').append(content);
//end of for loop
};
}
});
}
// First call with default orderBy value
newsFeed('newest');
$("#selector").change(function(){
$('#news').empty(); //remove all child nodes
orderBy = $("#orderBy :selected").text();
newsFeed(orderBy);
});
});
You need to arrange your code like this :
$(document).ready(function() {
var api = '//www.url.com'
var search = 'search?'
var orderBy = 'newest'
var url = api + search + orderBy
$("#selector").change(function(){
$('#news').empty(); //remove all child nodes
orderBy = $("#orderBy :selected").text();
newsFeed();
});
//API Call Setup
function newsFeed(data) {
$.ajax({
url: url,
success: function results(data) {
for (var i =0; i < data.response.total; i++) {
var content = '<li>' + data.response.results[i] + '</li>';
$('#news').append(content);
//end of for loop
};
}
});
}
newsFeed();
});
THE PROMPT: We have a search that connects to an JSON API url. The search query is inside the url, and the API generates a new JSON file for every search term. We also cannot rely on the browser to cache for us, and we can't use PHP or server side caching; we need to use HTML5 LocalStorage (and we don't care that IE7 can't use it)
We need to cache every new JSON file for every new search. We want to cut down on requests per minute, so we want to use a cached version of the JSON file for repeated search terms.
WHERE I'M STUCK: What has made this difficult is caching a JSON file for each new/different search term. I have been able to cache the first search, but then all subsequent searches use the same cached JSON.
We need help rewriting this so each time a new search is made, it checks to see if the term was searched for previously and if so, grabs the corresponding JSON file. Then of course if the search term is new then cache a new JSON file for that specific search term.
WHAT I'VE TRIED: In my research I've seen a lot of very complicated solutions and I can't seem to get my head completely around all of it, some of these solutions almost worked, I think I just need a better explanation for this specific case.
I think this is the answer but I don't know how to apply it to my situation: jQuery deferred ajax cache
This is crazy and it almost works, it writes into the console when it recognizes that I've searched the same thing again, and it does stop a new request, but unfortunately the cached JSON isn't there, it returns no results.
Caching a jquery ajax response in javascript/browser
WHAT I HAVE SO FAR:
MY PSUEDO CODE:
var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX
// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';
// Local Storage Caching Promise
var cachedData = localStorage.getItem("cachedData"),
def = $.Deferred();
if (!cachedData) {
def = $.getJSON(url, function(data) {
cachedData = data;
localStorage.setItem("cachedData", JSON.stringify(cachedData));
});
}
else{
cachedData = JSON.parse(cachedData);
def.resolve();
}
def.done(function() {
var resultHTML = '';
for(var i = 0; i < Object.keys(cachedData.things).length; i++){
$.each(cachedData, function(index, node){
resultHTML += '<li>'
resultHTML += '<h1>' + node[i].name + '</h1>';
resultHTML += '</li>';
});
}
$('div#results').html(resultHTML);
});
EXAMPLE JSON:
{
"things": [
{
"type": "thing",
"username": "randoguy",
"name": "name001",
},
{
"type": "thing2",
"username": "randoguy2",
"name": "name002",
},
...
Thank you #Ian for providing the hints to my answer!
var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX;
// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';
// BABAM! Right here, SearchTerm + "-cachedData" gets unique cached data
var cachedData = localStorage.getItem(searchTerm + "-cachedData"),
def = $.Deferred();
if (!cachedData) {
def = $.getJSON(url, function(data) {
cachedData = data;
// BABAM! And here is where the unique cachedData is set! SearchTerm + "-cachedData"
localStorage.setItem(searchTerm + "-cachedData", JSON.stringify(cachedData));
});
}
else{
cachedData = JSON.parse(cachedData);
def.resolve(cachedData);
}
def.done(function(data) {
var resultHTML = '';
for(var i = 0; i < Object.keys(data.repositories).length; i++){
$.each(data, function(index, node){
resultHTML += '<li>'
resultHTML += '<h1>' + node[i].name + '</h1>';
resultHTML += '<p>' + node[i].owner + '</p>';
resultHTML += '</li>';
});
}
$('div#results').html(resultHTML);
});
Where would I be without StackOverflow. Thank you all!
So, I've got the below code: -
function testing(results) {
$table = $('#formList')
for (var event in results) {
var formIDX = results[event]["forms_idx"]
var formID = results[event]["form_id"]
var eventIDX = results[event]["events_idx"]
var eventID = results[event]["event_id"]
var objID = results[event]["object_id"]
var testVal = results[event]["value"]
alert($table.find("#" + formIDX).find('td:eq(1)').find("div").find("table").html())
$subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
var url ="http://localhost:3278/FARTFramework/testScenario/ajaxPopulateSubTables"
$.post(url, {
formID: formID, eventIDX:eventIDX, eventID:eventID, objID:objID, testVal:testVal
}, function(data) {
$subTable.append(data);
}).done(function(){});
}
}
It basically takes a JSON file and then adds the data into the right sub tables within a main table via appends etc.
The oddity is during debug I had an alert in there to check the html of the table it was identifying (making sure it had found the right sub table etc) and all worked well. But if I remove that alert it then suddenly only appends all the data to the last sub table in the main table?! Any clues?
It's a classic JavaScript closure-loop problem. The variables defined in the for loop are being reassigned each time within the loop and responses from the AJAX requests(which are async) get appended to the last sub-table. It works when you have an alert because the variables have not been reassigned(as alert blocks the for loop execution) by the time AJAX request is completed.
You could handle this by having a function do the AJAX request and append. The variables are not reassigned within this function and hence should work.
function testing(results) {
$table = $('#formList')
function appendSubTable(formIDX, formID, eventIDX, eventID, objID, testVal){
alert($table.find("#" + formIDX).find('td:eq(1)').find("div").find("table").html())
var $subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
var url ="http://localhost:3278/FARTFramework/testScenario/ajaxPopulateSubTables"
$.post(url, {
formID: formID, eventIDX:eventIDX, eventID:eventID, objID:objID, testVal:testVal
}, function(data) {
$subTable.append(data);
}).done(function(){});
}
for (var event in results) {
var formIDX = results[event]["forms_idx"]
var formID = results[event]["form_id"]
var eventIDX = results[event]["events_idx"]
var eventID = results[event]["event_id"]
var objID = results[event]["object_id"]
var testVal = results[event]["value"]
appendSubTable(formIDX, formID, eventIDX, eventID, objID, testVal);
}
}
Without seeing more of your code, I can't say for sure. But when I had a similar issue it was because I was using append outside of my $(document).ready(function(){ /*stuff here*/ })
Essentially the object I was appending to hadn't loaded yet.
in your Ajax call use its argument 'async';
it accepts Boolean value, pass the value 'false' in it.
Try it
Move
$subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
To your callback function:
$.post(url, {
formID: formID, eventIDX:eventIDX, eventID:eventID, objID:objID, testVal:testVal
}, function(data) {
$subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
$subTable.append(data);
}).done(function(){});
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!
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
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
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.