Creating a dynamic dialog launcher menu for Dynamics CRM (FetchXML style)

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>&nbsp;&nbsp;" );  
});  
}

Wrapping up

Once those four changes are made, this web resource will behave exactly like the OData version.

comments powered by Disqus