Last month I wrote a post about how to create a web resource dialog "launcher" that you can embed in a CRM form (both classic and updated modes) with JavaScript and an OData query. In today's post, I will show how to do the same thing using a FetchXML query. There are four changes you need to make to the web resource from the previous post.
ClientGlobalContext.js.aspx
First, because we're working with FetchXML, you need to add a reference to ClientGlobalContext.js.aspx JavaScript to your page head.
Add the buildFetchRequest function
You need to add a function to build a full SOAP request from a FetchXML query. This is the same buildFetchRequest function I have used in previous FetchXML-related posts.
function buildFetchRequest(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;
}
Update the getDialogList function
You also need to update the getDialogList function to build and execute a FetchXML query instead of an OData query. Here is the updated function:
//function to retrieve the dialogs
function getDialogList() {
var dialogname = dataObj["dialogname"];
var entitytypename = dataObj["entitytypename"];
//only execute query if the record already exists
if((recordId != null) && (recordId != '')) {
//no point if entitytypename is provided
if((entitytypename != null) && (entitytypename != ''))
{
//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";
var fetchQuery = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">';
fetchQuery += '<entity name="workflow">';
fetchQuery += '<attribute name="workflowid" />';
fetchQuery += '<attribute name="name" />';
fetchQuery += '<attribute name="category" />';
fetchQuery += '<attribute name="primaryentity" />';
fetchQuery += '<attribute name="type" />';
fetchQuery += '<attribute name="description" />';
fetchQuery += '<order attribute="name" descending="false" />';
fetchQuery += '<filter type="and">';
fetchQuery += '<condition attribute="name" operator="like" value="'+dialogname+'%" />';
fetchQuery += '<condition attribute="type" operator="eq" value="1" />';
fetchQuery += '<condition attribute="category" operator="eq" value="1" />';
fetchQuery += '<condition attribute="primaryentityname" operator="eq" value="'+entitytypename+'" />';
fetchQuery += '</filter>';
fetchQuery += '</entity>';
fetchQuery += '</fetch>';
var fetchRequest = buildFetchRequest(fetchQuery);
$.ajax({
type: "POST",
dataType: "xml",
contentType: "text/xml; charset=utf-8",
processData: false,
url: path,
data: fetchRequest,
//complete: function(xhr, status) {
// console.log(xhr.responseText);
//},
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(function(data) {
//if successful, pass returned xml to the display function
generateLauncherMenu(data);
}).fail(function(jqXHR, textStatus, errorThrown ) {
//if unsuccessful, generate an error alert message
alert( "Request failed: " + textStatus + "\n" + errorThrown );
});
}
}
Update the generateLauncherMenu function
Finally, you need to update the generateLauncherMenu function to accept an XML input parameter and parse/process accordingly. Here is an updated version that, as in my previous example, generates buttons to launch the dialogs:
//callback function to parse the response and build the menu output
function generateLauncherMenu(xml) {
$(xml).find("a\\:Entity").each(function() {
var workflowid, primaryentity, name, paramString;
//inner loop
$(this).find("a\\:KeyValuePairOfstringanyType").each(function() {
var xmlElement = $(this);
var key = xmlElement.find("b\\:key").text();
var value = xmlElement.find("b\\:value").text();
switch(key) {
case "workflowid":
workflowid = value;
break;
case "primaryentity":
primaryentity = value;
break;
case "name":
name = value;
break;
}
paramString = "\"" + workflowid + "\",\"" + primaryentity + "\",\"" +recordId + "\"";
});
$('#launchDiv').append( "<button onclick='openDialog("+paramString+")'>Launch " + name + "</button> " );
});
}
Wrapping up
Once those four changes are made, this web resource will behave exactly like the OData version.