<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[jQuery - Alexander Development]]></title><description><![CDATA[jQuery - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>jQuery - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Fri, 24 Apr 2026 14:14:18 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/jquery/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Automatically executing HTTP POST requests in Dynamics 365 iframes - part 2]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Several months ago, I wrote a <a href="https://alexanderdevelopment.net/post/2016/09/09/automatically-executing-http-post-requests-in-dynamics-crm-iframes/">post</a> that showed how to automatically display the results of an HTTP POST request inside a Dynamics 365 iframe. I was working on a project last week where I was tried to use that approach, but I ran into some problems, so today I</p></div>]]></description><link>https://alexanderdevelopment.net/post/2017/07/10/automatically-executing-http-post-requests-in-dynamics-365-iframes-part-2/</link><guid isPermaLink="false">5a5837246636a30001b978bc</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Dynamics 365]]></category><category><![CDATA[integration]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 10 Jul 2017 21:48:55 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2017/07/posting-flow-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2017/07/posting-flow-1.png" alt="Automatically executing HTTP POST requests in Dynamics 365 iframes - part 2"><p>Several months ago, I wrote a <a href="https://alexanderdevelopment.net/post/2016/09/09/automatically-executing-http-post-requests-in-dynamics-crm-iframes/">post</a> that showed how to automatically display the results of an HTTP POST request inside a Dynamics 365 iframe. I was working on a project last week where I was tried to use that approach, but I ran into some problems, so today I will present an updated approach.</p>
<p>Specifically, my iframe needed to post a key value that was retrieved asynchronously by a function that was called when the main CRM form loaded. Because the iframe was contained in a collapsed tab, the iframe might not be loaded by the time the main form's script had retrieved the key value, so trying to dynamically write out HTML to the iframe wouldn't work like I showed previously. I tried a few different ways to trigger the &quot;write a dynamic form and submit it&quot; code after retrieving the key value, but I never could get it working consistently with an iframe in a collapsed tab.</p>
<p>The solution I found was to create a new helper HTML web resource and then load that into the iframe when the main form loads. The helper page then used an onload event to check to see if the main form's script had retrieved the key value for posting yet. Once the key value was available, then the helper page used it to execute the form submission. The passing of the key value from the main form to the helper page was handled with the JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">postMessage</a> function. Here's what that flow looked like:<br>
<img src="https://alexanderdevelopment.net/content/images/2017/07/posting-flow.png#img-thumbnail" alt="Automatically executing HTTP POST requests in Dynamics 365 iframes - part 2"></p>
<p>Here's the code I am running in the main CRM form:</p>
<pre><code>var _keyvalue = '';

var form_OnLoad = function (){
	//add a listener for the message from the iframe
	window.addEventListener('message', receiveMessage, false);
	Xrm.Page.ui.controls.get('NAME_OF_YOUR_IFRAME').setSrc('PATH_TO_YOUR_HELPER_RESOURCE');

	//run some other code that sets the value of _keyvalue asynchronously 
	//...
	//...
}    

var receiveMessage = function (event){
	//make sure that we are only responding to messages from the same origin as the CRM form
	var originarr = Xrm.Page.context.getClientUrl().split('/');
	originarr.pop();
	var origin = originarr.join('/');
	
	//if not, return
	if (event.origin !== origin)
		return;
	
	//if the received message is &quot;getkeyvalue,&quot; send a response
	if(event.data == 'getkeyvalue'){
		event.source.postMessage(_keyvalue, event.origin);
	}
}
</code></pre>
<p>Here is the code for the helper page:</p>
<pre><code>&lt;html&gt;
&lt;head&gt;
	&lt;title&gt;helper page&lt;/title&gt;
	&lt;script src=&quot;ClientGlobalContext.js.aspx&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;script src=&quot;https://code.jquery.com/jquery-2.2.4.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;script&gt;
	//default the keyvalue to an empty string
	var _keyvalue = '';

	var receiveMessage = function (event){
		//make sure that we are only responding to messages from the same origin as the CRM form
		var originarr = Xrm.Page.context.getClientUrl().split('/');
		originarr.pop();
		var origin = originarr.join('/');
		if (event.origin !== origin)
			return;
		
		if(event.data){
			_keyvalue = event.data;
		}
	}

	//start checking for the keyvalue from the parent form when the document is ready
	$(function(){
		//register the message listener
		window.addEventListener(&quot;message&quot;, receiveMessage, false);
		var checkinterval = null;
		var waittime = 100; //check every X ms
		checkinterval = setInterval(
			function(){
				//ask the parent for the keyvalue
				var originarr = Xrm.Page.context.getClientUrl().split('/');
				originarr.pop();
				var origin = originarr.join('/');
				parent.postMessage('getkeyvalue', origin);
				
				//if parent form has responded with a non-empty keyvalue
				if(_keyvalue!=''){
					//stop the cycle
					clearInterval(checkinterval);
					
					//set the value of the form input
					$('#keyvalue').attr('value',_keyvalue);

					//submit the form
					$('form').submit();
				}
			}, waittime
		);
	});
	&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
	Loading . . .
	&lt;form id=&quot;webpartform&quot; method=&quot;POST&quot; action=&quot;SOME_DESTINATION&quot;&gt;
		&lt;input type=&quot;hidden&quot; name=&quot;keyvalue&quot; id=&quot;keyvalue&quot; value=&quot;&quot; /&gt;
	&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Two additional points:</p>
<ol>
<li>My implementation is actually a bit more sophisticated than what I've shared here. Instead of just passing a string key value, I pass a JSON object that contains the key value and the correct URL for the form action so that I can use the same helper page for multiple targets. Once you get the postMessage calls working between a parent CRM form and its iframe(s), you can handle many different complex scenarios.</li>
<li>I suspect this approach is on right on the edge of the supported/unsupported line. The <a href="https://msdn.microsoft.com/en-us/library/hh771584.aspx">SDK documentation for using JavaScript</a> does say not to access the Document Object Model (DOM). Technically this approach uses the Browser Object Model (BOM), so it's not explicitly unsupported, but I could see changes to Dynamics 365 impacting it in the future, so that's just something to keep in mind.</li>
</ol>
</div>]]></content:encoded></item><item><title><![CDATA[Automatically executing HTTP POST requests in Dynamics CRM iframes]]></title><description><![CDATA[<div class="kg-card-markdown"><p>The Dynamics CRM SDK allows you to set the source URL for an iframe control on a form, and that is fine if all you need to do is load web pages that are accessible via HTTP GET requests. If you need to automatically display the results of an HTTP</p></div>]]></description><link>https://alexanderdevelopment.net/post/2016/09/09/automatically-executing-http-post-requests-in-dynamics-crm-iframes/</link><guid isPermaLink="false">5a5837246636a30001b9783e</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Fri, 09 Sep 2016 17:57:12 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2016/09/chrome_2016-09-09_12-44-43.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2016/09/chrome_2016-09-09_12-44-43.png" alt="Automatically executing HTTP POST requests in Dynamics CRM iframes"><p>The Dynamics CRM SDK allows you to set the source URL for an iframe control on a form, and that is fine if all you need to do is load web pages that are accessible via HTTP GET requests. If you need to automatically display the results of an HTTP POST request inside an iframe, it's a bit more challenging. Today I will show an approach that I have used to implement this functionality.</p>
<p>This approach uses a Dynamics CRM form JavaScript library to do the following:</p>
<ol>
<li>Dynamically create an HTML form in the iframe using regular JavaScript.</li>
<li>Dynamically append hidden form inputs with the correct parameter names and values using jQuery.</li>
<li>Submit the form using jQuery.</li>
</ol>
<pre><code>function iframePost(data, url, iframename, formid) {
  //get reference to iframe using supported crm sdk approach
  var iFrame = Xrm.Page.ui.controls.get(iframename);

  //get reference to iframe guts using plain old javascript
  var iFrameDoc = iFrame.getObject().contentWindow.document;

  //overwrite anything in the iframe with an empty form
  iFrameDoc.write('&lt;html&gt;&lt;body&gt;&lt;form id=&quot;'+formid+'&quot; method=&quot;POST&quot; action=&quot;'+url+'&quot;&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;');

  //loop through json object attributes to add form inputs
  $.each(data, function(n,v){
    $(iFrameDoc).find('#'+formid).append('&lt;input type=&quot;hidden&quot; name=&quot;' + n + '&quot; value=&quot;' + v + '&quot; /&gt;');
  });

  //submit the form
  $(iFrameDoc).find('#'+formid).submit();
}
</code></pre>
<p>This function expects the parameters to be supplied to the POST endpoint as a JSON object. Here's an example of how to use it. Assume the following:</p>
<ol>
<li>The target URL for the form POST is <a href="http://example.org/testservice">http://example.org/testservice</a>.</li>
<li>&quot;IFRAME_TESTFRAME&quot; is the name of the iframe where you want to display the results.</li>
<li>Input parameters are:
<ol>
<li>color = 'blue'</li>
<li>team = 'Auburn'</li>
</ol>
</li>
</ol>
<p>Your JavaScript code would look like this:</p>
<pre><code>var targeturl = 'http://example.org/testservice';

var iframename = 'IFRAME_TESTFRAME';

var formid = 'myform'; //This is the id of the dynamically generated form. You can call it whatever you want.

var formparams = {};
formparams.color = 'blue';
formparams.team = 'Auburn';

iframePost(formparams, targeturl, iframename, formid);
</code></pre>
<p><em>(It should go without saying that you need to make a jQuery library available to your CRM form, too.)</em></p>
<p>And that's all there is to it. Have you needed to do anything similar in your CRM projects? What approach did you take? Please share in the comments!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Easy HTML Formatting for Comments in Orchard Using Markdown]]></title><description><![CDATA[<div class="kg-card-markdown"><p>I recently moved this site from BlogEngine.NET to Orchard, and I decided I wanted to offer some basic HTML formatting (bold, italic, hyperlinks, etc.) functionality for comments, but I didn't want to do any significant amount of coding. After some research I realized that <a href="http://daringfireball.net/projects/markdown">Markdown</a> syntax would be the</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/07/07/easy-html-formatting-for-comments-in-orchard-using-markdown/</link><guid isPermaLink="false">5a5837216636a30001b976c1</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[Orchard CMS]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 08 Jul 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>I recently moved this site from BlogEngine.NET to Orchard, and I decided I wanted to offer some basic HTML formatting (bold, italic, hyperlinks, etc.) functionality for comments, but I didn't want to do any significant amount of coding. After some research I realized that <a href="http://daringfireball.net/projects/markdown">Markdown</a> syntax would be the easiest way to let my visitors add HTML to their comments, and I could enable it with just a few bits of JavaScript.</p>
<p>This solution involves three parts:</p>
<ol>
<li>Enable Markdown-&gt;HTML conversion on the client side using JavaScript.</li>
<li>Add a JavaScript function to trigger the conversion when comments are displayed to site visitors.</li>
<li>Update the Orchard ListOfComments shape to support the scripts in steps 1 and 2.</li>
</ol>
<h4 id="enablingmarkdownhtmlconversion">Enabling Markdown-&gt;HTML conversion</h4>
<p>First, we need to enable Markdown-&gt;HTML conversion in the browser via JavaScript. For this, I chose <a href="https://code.google.com/p/pagedown/wiki/PageDown">PageDown</a>, which is what StackOverflow uses for Markdown previewing. The PageDown project includes three JavaScript files:</p>
<ol>
<li>Markdown.Converter.js - This does the Markdown-&gt;HTML conversion.</li>
<li>Markdown.Sanitizer.js - This lets you whitelist the HTML tags you want to allow. For example, you don't want to render script tags.</li>
<li>Markdown.Editor.js - This enables a live preview of the Markdown-&gt;HTML conversion. I decided not to use this now because I am am only allowing extremely basic functionality like hyperlinks, lists, bolds and italics. Maybe someday I will revisit this.</li>
</ol>
<p>Download the Markdown.Converter.js and Markdown.Sanitizer.js from the PageDown project source. You may want to change the list of HTML tags that you want to render. If so, open the Markdown.Sanitizer.js file and find the following line to remove or add tags as appropriate.</p>
<pre><code>var basic_tag_whitelist = /^(&lt;\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)&gt;|&lt;(br|hr)\s?\/?&gt;)$/i;
</code></pre>
<p>Once you have made any changes to the Markdown.Sanitizer.js file, update your theme to include them in your Orchard-generated pages. In my case, I added them to my theme's Scripts directory and then added these two lines to my Layout.cshtml file:</p>
<pre><code> Script.Include(&quot;Markdown.Converter.js&quot;);  
 Script.Include(&quot;Markdown.Sanitizer.js&quot;);
</code></pre>
<h4 id="renderinganddisplayinghtmlformattedcomments">Rendering and displaying HTML-formatted comments</h4>
<p>Once you have the PageDown scripts added to your theme, you will have the capability to render HTML from Markdown, but you need to actually turn it on for comments. I found the easiest way to do this was to use JavaScript to replace the text of the body of each comment with the PageDown-generated HTML when the comment list is displayed. With jQuery this is simple. Just write a function that does the transformation for every P element of a specific class. Here's the code:</p>
<pre><code>$(document).ready(function () {  
 //var converter = new Markdown.Converter();  
 var converter = Markdown.getSanitizingConverter();  
 $('p.commentbody').each(function (ix, commentbody) {  
 var convertedhtml = converter.makeHtml($(commentbody).html());  
 $(commentbody).html(convertedhtml);  
 })  
});
</code></pre>
<p>I created a separate JavaScript file to hold that function that I call CommentMarkdownApply.js. This file also is placed in my theme's Scripts folder and loaded via a Script.Include call in the Layout file.</p>
<h4 id="updatingtheshape">Updating the shape</h4>
<p>Finally you need to wrap the comments' body text with the &quot;commentbody&quot; class that is used in the CommentMarkdownApply script and remove the automatic conversion of newlines to <br> tags that Orchard does when it renders comments. Individual comments are rendered via the ListOfComments shape, so you can create or update an alternate ListOfComments.cshtml file with the changes. To override the standard comment body display, you would just change this</p>
<pre><code>&lt;p class=&quot;text&quot;&gt;@(new MvcHtmlString(Html.Encode(comment.Record.CommentText).Replace(&quot;\r\n&quot;, &quot;&lt;br /&gt;\r\n&quot;)))&lt;/p&gt;
</code></pre>
<p>to</p>
<pre><code>&lt;p class=&quot;commentbody&quot;&gt;@(new MvcHtmlString(Html.Encode(comment.Record.CommentText)))&lt;/p&gt;
</code></pre>
<p>Upload all your new theme files and you're done. Happy blogging!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Creating a dynamic dialog launcher menu for Dynamics CRM (FetchXML style)]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last month I wrote a <a href="https://alexanderdevelopment.net/post/2013/05/17/Creating-a-dynamic-dialog-launcher-menu-for-Dynamics-CRM">post</a> about how to create a web resource dialog &quot;launcher&quot; 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</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/06/02/creating-a-dynamic-dialog-launcher-menu-for-dynamics-crm-fetchxml-style-2/</link><guid isPermaLink="false">5a5837226636a30001b97755</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[process automation]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 03 Jun 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Last month I wrote a <a href="https://alexanderdevelopment.net/post/2013/05/17/Creating-a-dynamic-dialog-launcher-menu-for-Dynamics-CRM">post</a> about how to create a web resource dialog &quot;launcher&quot; 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.</p>
<p><strong>ClientGlobalContext.js.aspx</strong></p>
<p>First, because we're working with FetchXML, you need to add a reference to ClientGlobalContext.js.aspx JavaScript to your page head.</p>
<p><strong>Add the buildFetchRequest function</strong></p>
<p>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 <a href="https://alexanderdevelopment.net/?tag=/FetchXML">FetchXML-related posts</a>.</p>
<pre><code>function buildFetchRequest(fetch) {  
/// &lt;summary&gt;  
/// builds a properly formatted FetchXML request  
/// based on Paul Way's blog post &quot;Execute Fetch from JavaScript in CRM 2011&quot;  
/// http://blog.customereffective.com/blog/2011/05/execute-fetch-from-javascript-in-crm-2011.html  
/// &lt;/summary&gt;  
var request = &quot;&lt;s:Envelope xmlns:s=\&quot;http://schemas.xmlsoap.org/soap/envelope/\&quot;&gt;&quot;;  
request += &quot;&lt;s:Body&gt;&quot;;   
  
request += '&lt;Execute xmlns=&quot;http://schemas.microsoft.com/xrm/2011/Contracts/Services&quot;&gt;' +   
'&lt;request i:type=&quot;b:RetrieveMultipleRequest&quot; ' +   
' xmlns:b=&quot;http://schemas.microsoft.com/xrm/2011/Contracts&quot; ' +   
' xmlns:i=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;' +   
'&lt;b:Parameters xmlns:c=&quot;http://schemas.datacontract.org/2004/07/System.Collections.Generic&quot;&gt;' +   
'&lt;b:KeyValuePairOfstringanyType&gt;' +   
'&lt;c:key&gt;Query&lt;/c:key&gt;' +   
'&lt;c:value i:type=&quot;b:FetchExpression&quot;&gt;' +   
'&lt;b:Query&gt;';  
  
request += CrmEncodeDecode.CrmXmlEncode(fetch);   
  
request += '&lt;/b:Query&gt;' +   
'&lt;/c:value&gt;' +   
'&lt;/b:KeyValuePairOfstringanyType&gt;' +   
'&lt;/b:Parameters&gt;' +   
'&lt;b:RequestId i:nil=&quot;true&quot;/&gt;' +   
'&lt;b:RequestName&gt;RetrieveMultiple&lt;/b:RequestName&gt;' +   
'&lt;/request&gt;' +   
'&lt;/Execute&gt;';   
  
request += '&lt;/s:Body&gt;&lt;/s:Envelope&gt;';   
return request;  
}  
</code></pre>
<p><strong>Update the getDialogList function</strong></p>
<p>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:</p>
<pre><code>//function to retrieve the dialogs  
function getDialogList() {  
var dialogname = dataObj[&quot;dialogname&quot;];  
var entitytypename = dataObj[&quot;entitytypename&quot;];   
  
//only execute query if the record already exists  
if((recordId != null) &amp;&amp; (recordId != '')) {  
  
//no point if entitytypename is provided  
if((entitytypename != null) &amp;&amp; (entitytypename != ''))  
{  
//path to CRM root  
var server = window.location.protocol + &quot;//&quot; + window.location.host;  
  
//full path to CRM organization service - you may need to modify this depending on your particular situation  
var path = server + &quot;/XRMServices/2011/Organization.svc/web&quot;;  
var fetchQuery = '&lt;fetch version=&quot;1.0&quot; output-format=&quot;xml-platform&quot; mapping=&quot;logical&quot; distinct=&quot;false&quot;&gt;';  
fetchQuery += '&lt;entity name=&quot;workflow&quot;&gt;';  
fetchQuery += '&lt;attribute name=&quot;workflowid&quot; /&gt;';  
fetchQuery += '&lt;attribute name=&quot;name&quot; /&gt;';  
fetchQuery += '&lt;attribute name=&quot;category&quot; /&gt;';  
fetchQuery += '&lt;attribute name=&quot;primaryentity&quot; /&gt;';  
fetchQuery += '&lt;attribute name=&quot;type&quot; /&gt;';  
fetchQuery += '&lt;attribute name=&quot;description&quot; /&gt;';  
fetchQuery += '&lt;order attribute=&quot;name&quot; descending=&quot;false&quot; /&gt;';  
fetchQuery += '&lt;filter type=&quot;and&quot;&gt;';  
fetchQuery += '&lt;condition attribute=&quot;name&quot; operator=&quot;like&quot; value=&quot;'+dialogname+'%&quot; /&gt;';  
fetchQuery += '&lt;condition attribute=&quot;type&quot; operator=&quot;eq&quot; value=&quot;1&quot; /&gt;';  
fetchQuery += '&lt;condition attribute=&quot;category&quot; operator=&quot;eq&quot; value=&quot;1&quot; /&gt;';  
fetchQuery += '&lt;condition attribute=&quot;primaryentityname&quot; operator=&quot;eq&quot; value=&quot;'+entitytypename+'&quot; /&gt;';  
fetchQuery += '&lt;/filter&gt;';  
fetchQuery += '&lt;/entity&gt;';  
fetchQuery += '&lt;/fetch&gt;';  
  
var fetchRequest = buildFetchRequest(fetchQuery);  
  
$.ajax({  
type: &quot;POST&quot;,  
dataType: &quot;xml&quot;,  
contentType: &quot;text/xml; charset=utf-8&quot;,  
processData: false,  
url: path,  
data: fetchRequest,  
//complete: function(xhr, status) {  
// console.log(xhr.responseText);  
//},  
beforeSend: function( xhr ){  
xhr.setRequestHeader(  
&quot;SOAPAction&quot;,  
&quot;http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute&quot;  
); //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( &quot;Request failed: &quot; + textStatus + &quot;\n&quot; + errorThrown );  
});  
}  
}  
</code></pre>
<p><strong>Update the generateLauncherMenu function</strong></p>
<p>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:</p>
<pre><code>//callback function to parse the response and build the menu output  
function generateLauncherMenu(xml) {  
$(xml).find(&quot;a\\:Entity&quot;).each(function() {  
var workflowid, primaryentity, name, paramString;  
//inner loop  
$(this).find(&quot;a\\:KeyValuePairOfstringanyType&quot;).each(function() {  
var xmlElement = $(this);  
var key = xmlElement.find(&quot;b\\:key&quot;).text();  
var value = xmlElement.find(&quot;b\\:value&quot;).text();  
switch(key) {  
case &quot;workflowid&quot;:  
workflowid = value;  
break;  
case &quot;primaryentity&quot;:  
primaryentity = value;  
break;  
case &quot;name&quot;:  
name = value;  
break;  
}  
paramString = &quot;\&quot;&quot; + workflowid + &quot;\&quot;,\&quot;&quot; + primaryentity + &quot;\&quot;,\&quot;&quot; +recordId + &quot;\&quot;&quot;;  
});  
$('#launchDiv').append( &quot;&lt;button onclick='openDialog(&quot;+paramString+&quot;)'&gt;Launch &quot; + name + &quot;&lt;/button&gt;&amp;nbsp;&amp;nbsp;&quot; );  
});  
}
</code></pre>
<p><strong>Wrapping up</strong></p>
<p>Once those four changes are made, this web resource will behave exactly like the OData version.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Creating a dynamic dialog launcher menu for Dynamics CRM]]></title><description><![CDATA[<div class="kg-card-markdown"><p>I love Dynamics CRM dialogs. In fact, I think they are one of the best features of CRM 2011. What I don't like about dialogs is how the user has to run them when working with a entity record. On a &quot;classic&quot; mode form, the user has to</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/05/16/creating-a-dynamic-dialog-launcher-menu-for-dynamics-crm/</link><guid isPermaLink="false">5a5837226636a30001b9774d</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[OData]]></category><category><![CDATA[process automation]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Fri, 17 May 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>I love Dynamics CRM dialogs. In fact, I think they are one of the best features of CRM 2011. What I don't like about dialogs is how the user has to run them when working with a entity record. On a &quot;classic&quot; mode form, the user has to go to the ribbon, click start dialog and then find the dialog in a list. If there are lots of dialogs for that entity type, the user then has to spend a lot of time looking, change the view or search. That experience is still better than on an &quot;updated&quot; mode forms where the user can't run dialogs at all without switching to classic mode. It is possible to launch a dialog via a URL from a web resource embedded in a CRM form using the format described <a href="http://msdn.microsoft.com/en-us/library/gg328483.aspx#BKMK_OpenADialogProcess">here</a>, but that approach requires you hardcode the GUID for the dialog you want to open. In this post I will show how to create a web resource dialog &quot;launcher&quot; that you can embed in a CRM form (both classic and updated modes) with JavaScript and an OData query.</p>
<p>Originally when I started looking at this, I was thinking about just a single dialog launch button, but then I remembered the <a href="https://alexanderdevelopment.net/post/2010/05/20/A-macros-system-for-Dynamics-CRM-part-one">&quot;macros&quot; system</a> I created originally for CRM 3, and I realized that a dynamic dialog menu would achieve a lot of the same goals without anywhere near as much custom code. That being said, the approach I am going to show will allow you to create a menu that displays either a single dialog or multiple dialogs depending on exactly how you want to make them available to your end users.</p>
<p><strong>Retrieving the dialogs</strong></p>
<p>First, we have to retrieve the dialogs. Normally, I am a big fan of using FetchXML for all my multi-record CRM data retrieval, but I decided to get the list of dialogs via OData because the query is extremely simple, and I doubt anyone will run into a situation where the number of dialogs to retrieve will exceed the OData maximum limit.</p>
<p>Here is an OData query for retrieving an account-related dialog named Lucas Demo Account Dialog:</p>
<pre><code>/WorkflowSet?$filter=Category/Value eq 1 and Type/Value eq 1 and StatusCode/Value eq 2 and PrimaryEntity eq 'account' and Name eq 'Lucas Demo Account Dialog' &amp;$select=Name, WorkflowId, Description, Category, Type, PrimaryEntity&amp;$orderby=Name
</code></pre>
<p>Let's take a closer look at the query parameters.</p>
<ol>
<li>The workflow set contains workflows and dialogs, so we use Category/Value eq 1 to get only dialogs.</li>
<li>In addition to containing workflow and dialog definitions (and templates), the workflow set contains a separate entry for each activation. That is if you create and activate a dialog, then deactivate / edit / reactivate, etc., you will see the same dialog name multiple times in the results. This is why we use Type/Value eq 1 to get only the actual definition.</li>
<li>A user can't execute a draft dialog, so we use StatusCode/Value eq 2 to retrieve only published dialogs.</li>
<li>PrimaryEntity eq 'account' is used to retrieve only dialogs related to the account entity.</li>
<li>Name eq 'Lucas Demo Account Dialog' returns only dialogs with the name of Lucas Demo Account Dialog.</li>
</ol>
<p>That query is fine if you only want users to be able to launch a single dialog from your menu, but what if you want to have multiple dialogs? The easiest way to do that is to remove the Name parameter, so a query for all account-related dialogs would look like this:</p>
<pre><code>/WorkflowSet?$filter=Category/Value eq 1 and Type/Value eq 1 and StatusCode/Value eq 2 and PrimaryEntity eq 'account' &amp; $select=Name, WorkflowId, Description, Category, Type, PrimaryEntity&amp;$orderby=Name
</code></pre>
<p>This is OK, but there's a better approach that will allow for retrieving single or multiple records without having to use a different query format. Here's the query:</p>
<pre><code>/WorkflowSet?$filter=Type/Value eq 1 and Category/Value eq 1 and StatusCode/Value eq 2 and PrimaryEntity eq 'account' and startswith(Name, 'XXX') &amp;$select=Name, WorkflowId, Description, Category, Type, PrimaryEntity&amp;$orderby=Name
</code></pre>
<p>Using the &quot;startswith&quot; operator gives you a lot more control. If you do startswith(Name, ''), you get everything. If you do startswith(Name, 'Lucas Demo Account Dialog'), you get just the single dialog (assuming you only have one dialog with that name/entity combination). This approach also allows you to show a subset of dialogs. Imagine you have two kinds of account dialogs, sales and service. If you prefix your sales dialogs with SALES- and your service dialogs with SVC-, you can filter the dialogs to build a service-only menu using the following query.</p>
<pre><code>/WorkflowSet?$filter=Type/Value eq 1 and Category/Value eq 1 and StatusCode/Value eq 2 and PrimaryEntity eq 'account' and startswith(Name, 'SVC-')&amp;$select=Name, WorkflowId, Description, Category, Type, PrimaryEntity&amp;$orderby=Name
</code></pre>
<p>At this point, we have everything we need from an OData query perspective to write a separate web resource for every entity/functional combination, but I think it's better to use a generic web resource that takes the entity and name parameters via a query string. Unfortunately JavaScript doesn't have native query string parsing capability, so we need to use a custom function to extract the query string values. This is based on something I found on <a href="http://stackoverflow.com/a/647272">Stack Overflow</a>.</p>
<pre><code>function parseQueryString(qs) {  
var result = {}, keyValuePairs = qs.split('&amp;');  
  
keyValuePairs.forEach(function(keyValuePair) {  
keyValuePair = keyValuePair.split('=');  
result[keyValuePair[0]] = keyValuePair[1] || '';  
});  
  
return result;  
}  
  
//For IE8- support include this tiny Array.forEach* polyfill:  
if ( !Array.prototype.forEach ) {  
Array.prototype.forEach = function(fn, scope) {  
for(var i = 0, len = this.length; i &lt; len; ++i) {  
fn.call(scope, this[i], i, this);  
}  
}  
}
</code></pre>
<p>We then decode the querystring like this:</p>
<pre><code>var queryObj = parseQueryString(location.search.slice(1));
</code></pre>
<p>Because we will be passing the dialog name and entity name to the web resource as custom parameter data, we have to URI decode the &quot;data&quot; object and then parse it. We can then pass the URI-decoded data object to the parseQueryString function to parse it like this:</p>
<pre><code>var dataObj = parseQueryString(decodeURIComponent(queryObj[&quot;data&quot;]));
</code></pre>
<p>With the query string fully parsed, here's the function to retrieve the list of dialogs.</p>
<pre><code>function getDialogList() {  
var dialogname = dataObj[&quot;dialogname&quot;];  
var entitytypename = dataObj[&quot;entitytypename&quot;];   
  
//only execute query if the record already exists  
if((recordId != null) &amp;&amp; (recordId != '')) {  
//set the path to the odata rest service  
//this can be hardcoded using the Organization Rest Service URL under Customizations-&gt;Developer Resources  
var odataPath = &quot;https://&quot; + window.location.host + &quot;/XRMServices/2011/OrganizationData.svc&quot;;  
  
//no point inif entitytypename is provided  
if((entitytypename != null) &amp;&amp; (entitytypename != ''))  
{  
//set up the odata query  
var retrieveReq = new XMLHttpRequest();  
var odataQuery = odataPath + &quot;/WorkflowSet?$filter=Type/Value eq 1 and Category/Value eq 1 and StatusCode/Value eq 2&quot;;  
odataQuery += &quot; and PrimaryEntity eq '&quot;+entitytypename+&quot;'&quot;;  
odataQuery += &quot; and startswith(Name, '&quot;+dialogname+&quot;')&quot;;  
odataQuery += &quot;&amp;$select=Name, WorkflowId, Description, Category, Type, PrimaryEntity&amp;$orderby=Name&quot;;  
retrieveReq.open(&quot;GET&quot;, odataQuery, false);  
  
//make sure we get json back  
retrieveReq.setRequestHeader(&quot;Accept&quot;, &quot;application/json&quot;);  
retrieveReq.setRequestHeader(&quot;Content-Type&quot;, &quot;application/json; charset=utf-8&quot;);  
  
//request/response will execute asynchronously, so we need a callback function  
retrieveReq.onreadystatechange = function () { generateLauncherMenu(this); };  
  
//send the request  
retrieveReq.send();  
}  
}  
}
</code></pre>
<p><strong>Generating the launcher menu</strong></p>
<p>Once the dialogs have been retrieved by the OData query, we can use jQuery to easily generate the contents of the launcher menu. There's lots of ways you can represent the dialogs to launch - buttons, hyperlinks, drop-down menu entries, etc. - but I think buttons are the best UI for a small set of dialogs.</p>
<p>The following function writes dialog-launching buttons to a div called launchDiv.</p>
<pre><code>function generateLauncherMenu(retrieveReq) {  
//4 means a complete response  
if (retrieveReq.readyState == 4) {   
//parse response to json  
var retrieved = this.parent.JSON.parse(retrieveReq.responseText).d;   
  
for (var i = 0; i &lt; retrieved.results.length; i++) {  
//create a button and append it to a launchdiv div  
var paramString = &quot;\&quot;&quot; + retrieved.results[i].WorkflowId + &quot;\&quot;,\&quot;&quot; + retrieved.results[i].PrimaryEntity+ &quot;\&quot;,\&quot;&quot; +recordId + &quot;\&quot;&quot;;  
$('#launchDiv').append( &quot;&lt;button onclick='openDialog(&quot;+paramString+&quot;)'&gt;Launch &quot;+retrieved.results[i].Name+&quot;&lt;/button&gt;&lt;br /&gt;&quot; );  
}  
};  
}
</code></pre>
<p>And then this function opens the dialog window:</p>
<pre><code>function openDialog(processId, primaryEntity, entityId) {  
var url = &quot;/cs/dialog/rundialog.aspx?DialogId=&quot; + processId + &quot;&amp;EntityName=&quot; + primaryEntity + &quot;&amp;ObjectId=&quot; + entityId.replace('{','').replace('}','');  
window.open(parent.Xrm.Page.context.getClientUrl() + url);  
}
</code></pre>
<p><strong>Putting it all together</strong></p>
<p>Here's the complete web page you can upload as a web resource to your CRM system: <a href="https://alexanderdevelopment.net/FILES%2f2013/05/dialog_launcher.htm.axdx">dialog_launcher.htm (3.91 kb)</a></p>
<p>All you have to do is embed the web resource on your entity form and set the properties and custom parameter data like in the following image:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/05/web_resource_embed.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/05/web_resource_embed.PNG#img-thumbnail" alt=""></a></p>
<p>I have two account dialogs in my CRM system, Demo-Dialog #1 and Demo-Dialog #2. This is what the launcher menu looks like in a pre-Polaris, read-only form:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/05/updated_form.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/05/updated_form.PNG#img-thumbnail" alt=""></a></p>
<p>Here is what it looks like in a classic-mode form:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/05/classic_form.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/05/classic_form.PNG#img-thumbnail" alt=""></a></p>
<p>As always, happy coding!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Displaying FetchXML results with XSLT on the client side in a Dynamics CRM 2011 web resource]]></title><description><![CDATA[<div class="kg-card-markdown"><p>A few weeks back, I wrote a post that showed <a href="https://alexanderdevelopment.net/post/2013/01/20/FetchXML-JQuery-in-a-Dynamics-CRM-2011-web-resource">how to retrieve and display FetchXML using jQuery in a Dynamics CRM web resource</a>. In that example, I used jQuery's each() method to iterate through each result and append them to an HTML element on the page. Using each() is</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/02/10/displaying-fetchxml-results-with-xslt-on-the-client-side-in-a-dynamics-crm-2011-web-resource/</link><guid isPermaLink="false">5a5837226636a30001b97726</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 11 Feb 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>A few weeks back, I wrote a post that showed <a href="https://alexanderdevelopment.net/post/2013/01/20/FetchXML-JQuery-in-a-Dynamics-CRM-2011-web-resource">how to retrieve and display FetchXML using jQuery in a Dynamics CRM web resource</a>. In that example, I used jQuery's each() method to iterate through each result and append them to an HTML element on the page. Using each() is a good approach if you need to actually do something with each row, but if you just want to display data, XSLT is a much easier way to do it. In this post, I will show how to use client-side XSLT to format a FetchXML response for display.</p>
<p><strong>Fetching the data</strong></p>
<p>To display data, obviously we need to retrieve some data first. Using the approach from my earlier post, we will use the following FetchXML query to return a list of contacts:</p>
<pre><code>&lt;fetch version=&quot;1.0&quot; output-format=&quot;xml-platform&quot; mapping=&quot;logical&quot; distinct=&quot;false&quot;&gt;  
&lt;entity name=&quot;contact&quot;&gt;  
&lt;attribute name=&quot;fullname&quot; /&gt;  
&lt;attribute name=&quot;contactid&quot; /&gt;  
&lt;attribute name=&quot;ownerid&quot; /&gt;  
&lt;attribute name=&quot;gendercode&quot; /&gt;  
&lt;attribute name=&quot;address1_stateorprovince&quot; /&gt;  
&lt;attribute name=&quot;createdon&quot; /&gt;  
&lt;/entity&gt;  
&lt;/fetch&gt;
</code></pre>
<p>When I execute this query, I get the output in the attached contacts.xml file: <a href="https://alexanderdevelopment.net/content/images/2013/02/contacts_raw.xml">contacts_raw.xml (50.68 kb)</a>.</p>
<p><strong>Designing the display format</strong></p>
<p>It we are going to use XSLT to format XML data, we will need an XSL style sheet. A detailed discussion of XSL is beyond the scope of this post, but I will point out a couple of things about my style sheet:</p>
<p>First, I use a template to match the root node, and then I loop through each entity with this for-each element:</p>
<p><em>&lt;xsl:for-each select=&quot;//a:Entities/a:Entity&quot;&gt;</em></p>
<p>The &quot;//a:Entities&quot; tells it to match an a:Entities element with any ancestors so you don't have to match all the way to the top-level s:Envelope ancestor.</p>
<p>Second, FetchXML represents an attribute (or formattedvalue) as an element with one &quot;key&quot; child and one &quot;value&quot; child. The &quot;key&quot; child is the attribute name, and the &quot;value&quot; is, obviously, the value. Thus, from each entity, I select the attribute and formattedvalue data to display using elements like this:</p>
<p><em>&lt;xsl:value-of select=&quot;a:Attributes/a:KeyValuePairOfstringanyType[b:key='fullname']/b:value&quot; /&gt;</em></p>
<p>What that means is &quot;select the 'b:value' element that has an 'a:KeyValuePairOfstringanyType' that has a 'b:key' element equal to 'fullname.'&quot; Alternatively, you can think abou it as &quot;select the 'b:value' element that has a sibling 'b:key' element equal to 'fullname.'&quot;</p>
<p>Here is the complete XSL style sheet: <a href="https://alexanderdevelopment.net/content/images/2013/02/contacts.xsl">contacts.xsl (1.35 kb)</a>.</p>
<p>Once you have your XSL style sheet ready, upload it to your CRM instance as a web resource of type &quot;Style Sheet (XSL).&quot; Make sure you remember the relative path of the new resource. In my case it is &quot;new_contacts.xsl.&quot;</p>
<p><strong>Applying the transformation</strong></p>
<p>Now that we have some FetchXML results and an XSL style sheet, all that's left to do is to transform the returned FetchXML and display it on the page. To do that, I have made a few modifications to my earlier FetchXML retrieval logic. Because jQuery retrieves things by default asynchronously, I start with retrieving the XSL document, then I use a callback function to retrieve the FetchXML results and finally I use a callback function to do the transformation. In the interest of not cluttering my code with global variables, I pass everything I need through the chain of callbacks. For example, my XSL retrieval method takes the FetchXML request as a parameter just so it can pass it to its callback. Then that callback takes the XSL document so that its callback has the XSL.</p>
<p>The code to do the apply and display the transformation is below:</p>
<pre><code>function processData(xml, xsl) {  
/// &lt;summary&gt;  
/// transforms xml with a supplied xsl style sheet and appends the output to a div on the page  
/// &lt;/summary&gt;  
  
//instantiate a variable to hold the transformed xml  
var resultDocument = &quot;&quot;;  
resultDocument = TransformToHtmlText(xml, xsl);  
alert(&quot;Output started&quot;);  
$(&quot;#outputdiv&quot;).append(resultDocument);  
  
alert(&quot;Output complete&quot;);  
}  
  
function TransformToHtmlText(xmlDoc, xsltDoc) {  
/// &lt;summary&gt;  
/// Transforms a XML document to a HTML string by using a XSLT document  
/// 1. Use type XSLTProcessor, if browser (FF, Safari, Chrome etc) supports it  
/// 2. Use function [transformNode] on the XmlDocument, if browser (IE6, IE7, IE8) supports it  
/// 3. Use function transform on the XsltProcessor used for IE9 (which doesn't support [transformNode] any more)   
/// 4. Throws an error, when both types are not supported  
/// taken from &quot;How to fix: DOMParser.TransformNode not supported in IE9&quot;  
/// http://www.roelvanlisdonk.nl/?p=2113  
/// &lt;/summary&gt;  
// 1.  
if (typeof (XSLTProcessor) != &quot;undefined&quot;) {  
var xsltProcessor = new XSLTProcessor();  
xsltProcessor.importStylesheet(xsltDoc);  
var xmlFragment = xsltProcessor.transformToFragment(xmlDoc, document);  
return xmlFragment;  
}  
// 2.  
if (typeof (xmlDoc.transformNode) != &quot;undefined&quot;) {  
return xmlDoc.transformNode(xsltDoc);  
}  
else {  
  
try {  
// 3  
if (window.ActiveXObject) {  
var xslt = new ActiveXObject(&quot;Msxml2.XSLTemplate&quot;);  
var xslDoc = new ActiveXObject(&quot;Msxml2.FreeThreadedDOMDocument&quot;);  
xslDoc.loadXML(xsltDoc.xml);  
xslt.style sheet = xslDoc;  
var xslProc = xslt.createProcessor();  
xslProc.input = xmlDoc;  
xslProc.transform();  
  
return xslProc.output;  
}  
}  
catch (e) {  
// 4  
alert(&quot;The type [XSLTProcessor] and the function [XmlDocument.transformNode] are not supported by this browser, can't transform XML document to HTML string!&quot;);  
return null;  
}  
  
}  
}
</code></pre>
<p>Two points to note:</p>
<ol>
<li>The processData method doesn't apply the transformation itself. It passes the XML and XSL to another method called TransformToHtmlText.</li>
<li>The TransformToHtmlText method allows us to easily handle differences in the way that different browsers (or even different versions of the same browser) handle XML. For more information take a look at <a href="http://www.roelvanlisdonk.nl/?p=2113">http://www.roelvanlisdonk.nl/?p=2113</a> and <a href="http://stackoverflow.com/questions/12149410/object-doesnt-support-property-or-method-transformnode-in-internet-explorer-1">http://stackoverflow.com/questions/12149410/object-doesnt-support-property-or-method-transformnode-in-internet-explorer-1</a>.</li>
</ol>
<p><strong>Trying it out</strong></p>
<p>Here is a complete web page with the code for you to download and try out in your own CRM instance: <a href="https://alexanderdevelopment.net/content/images/2013/02/fetchxml_xslt.htm">fetchxml_xslt.htm (7.02 kb)</a>. Just upload it as you would any other web resource, publish and open. At that point you will be presented with a screen that looks like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/02/fetch_start.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/02/fetch_start.PNG#img-thumbnail" alt="The FetchXML / jQuery / XSLT example page"></a></p>
<p>Either leave the pre-populated FetchXML in the textarea or supply your own. Once you click the &quot;fetch and process&quot; button, you will start to see some output and a couple of status alert windows before the output finally displays. The end result should look something like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/02/fetch_complete.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/02/fetch_complete.PNG#img-thumbnail" alt="The FetchXML / jQuery / XSLT example page showing output"></a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Better line charts in Dynamics CRM 2011 - part II]]></title><description><![CDATA[<div class="kg-card-markdown"><p>In <a href="https://alexanderdevelopment.net/post/2013/01/24/Better-Line-Charts-in-Dynamics-CRM-2011-part-I.aspx">part I</a> of this series, I showed how to query Microsoft Dynamics CRM for aggregate data using FetchXML and then pass the results to <a href="http://www.flotcharts.org">Flot</a> to generate a line chart. In this second part, I will expand on that to show how to query for and chart multi-series data.</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/01/26/better-line-charts-in-dynamics-crm-2011-part-ii/</link><guid isPermaLink="false">5a5837216636a30001b97697</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[data visualizations]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Sun, 27 Jan 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>In <a href="https://alexanderdevelopment.net/post/2013/01/24/Better-Line-Charts-in-Dynamics-CRM-2011-part-I.aspx">part I</a> of this series, I showed how to query Microsoft Dynamics CRM for aggregate data using FetchXML and then pass the results to <a href="http://www.flotcharts.org">Flot</a> to generate a line chart. In this second part, I will expand on that to show how to query for and chart multi-series data. For my example today, I will be creating a chart that shows the number of contacts created by date and state (address, not statecode). In my CRM instance, I have created a set of contacts using characters from Cohen brothers movies. (Please, hold your &quot;Big Lebowski&quot; quotes.)</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/contacts.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/contacts.PNG#img-thumbnail" alt="Contacts"></a></p>
<p><strong>Changes to the previous approach</strong></p>
<p>There are three main things we have to do differently here than before:</p>
<ol>
<li>Update the FetchXML query to include an additional group-by field</li>
<li>Update the results parser to handle the additional group-by field</li>
<li>Send Flot an array of data series instead of just one</li>
</ol>
<p>In addition to that, I have improved the original code in two more ways:</p>
<ol>
<li>Fill in missing date values with 0 so the shape of the line better reflects reality</li>
<li>Shade weekend days in gray on the chart grid to help break up the weeks and highlight areas in which we might logically expect no activity to occur</li>
</ol>
<p><strong>Updated FetchXML</strong></p>
<p>Changing the FetchXML query is easy. We just have to add the address1_stateorprovince field:</p>
<pre><code>&lt;fetch distinct='false' mapping='logical' aggregate='true'&gt;  
&lt;entity name='contact'&gt;  
&lt;attribute name='fullname' alias='plotValue' aggregate='count' /&gt;  
&lt;attribute name='address1_stateorprovince' groupby='true' alias='seriesLabel' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='day' alias='day' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='month' alias='month' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='year' alias='year' /&gt;  
&lt;/entity&gt;  
&lt;/fetch&gt;
</code></pre>
<p>The field we will use to create the data series is aliased as &quot;seriesLabel&quot; so we can have as generic a results parsing method as possible.</p>
<p><strong>Updated results parser</strong></p>
<p>The manner in which I wrote the getKeyValPairs function in part I won't return the seriesLabel field as part of the return object because only the numeric values come back in the a:FormattedValues element. The seriesLabel field is available via the a:Attributes element, so this required a minor change to my XML find logic. If you have downloaded my previous charting sample, you should be able to update the getKeyValPairs function in it with the newer version here without any issues.</p>
<pre><code>function getKeyValPairs(entity, valuefield) {  
/// &lt;summary&gt;  
/// extracts an aggregate value and grouping components from a FetchXML response entity element and returns them in an array  
/// &lt;/summary&gt;  
var outputArray = new Array();  
  
//first, get the aggregate value using its alias (&quot;plotValue&quot; in the original example)  
var pointValue = parseFloat(entity.find(&quot;a\\:KeyValuePairOfstringstring&quot;).filter(function() {  
return $(this).find('b\\:key').text() == valuefield;  
}).find(&quot;b\\:value&quot;).text().replace(/,/g,''));  
var groupingArray = [];  
  
//second, get the values for the group-by fields  
//unlike previous example, this uses the a:KeyValuePairOfstringanyType element   
//so we go down an extra &quot;value&quot; level when populating the value variable  
entity.find(&quot;a\\:KeyValuePairOfstringanyType&quot;).each(function() {  
return $(this).find('b\\:key').text() != valuefield;  
}).each(function() {  
var xmlElement = $(this);  
var key = xmlElement.find(&quot;b\\:key&quot;).text();  
var value = xmlElement.find(&quot;b\\:value&quot;).find(&quot;a\\:Value&quot;).text();  
var groupingText = '&quot;' + key + '&quot;:&quot;' + value + '&quot;';  
groupingArray.push(groupingText);  
});  
var stringToEval = groupingArray.join();  
var dateFields = eval(&quot;({&quot;+stringToEval+&quot;})&quot;);  
outputArray.push(pointValue);  
outputArray.push(dateFields);  
  
return outputArray;  
}
</code></pre>
<p><strong>Sending Flot the data</strong></p>
<p>Flot expects data to be passed as an array of objects like this:</p>
<pre><code>{   
label: &quot;Series Label&quot;,   
data: [[x1,y1],[x2,y2]...   
}
</code></pre>
<p>In our example, we would have a separate object for each state's data. To build the array of data objects, we do the following:</p>
<ol>
<li>Get a list of unique series labels (states)</li>
<li>Create a holding array for each series' data points</li>
<li>Assign each data point to its correct series in the holding array</li>
<li>Build the data array Flot expects from the holding array</li>
</ol>
<p>As part of building the data array for Flot, we also do some date manipulation to fill in missing dates with 0 values.</p>
<p>Here are the functions that do all of this:</p>
<pre><code>function processData(xml) {  
/// &lt;summary&gt;  
/// charts data returned in a FetchXML response using Flot  
/// &lt;/summary&gt;  
  
alert(&quot;Charting started&quot;);  
  
//array to hold series labels  
var seriesList = [];  
  
//array to hold the series data before we get it ready for flot  
var pointSeries = [];  
  
//array to hold data to pass to flot  
var dataSeries = [];  
  
//array to hold all each unique date in our data set   
//this is so we can show dates with no data between the start and finish dates as 0  
var dateArray = [];  
  
//loop through xml and extract data from each &quot;entity&quot; element  
$(&quot;#chartdiv&quot;).append(&quot;Starting XML parsing . . . &lt;br /&gt;&quot;);  
$(xml).find(&quot;a\\:Entity&quot;).each(function() {  
//pass the element to a function that extracts the aggregate value and the &quot;group by&quot; values  
//&quot;plotValue&quot; is the FetchXML alias for the data we want to display  
var pointData = getKeyValPairs($(this),&quot;plotValue&quot;);   
  
//for each unique series label value  
if(seriesList.indexOf(pointData[1].seriesLabel) == -1) {  
//add label to array of labels  
seriesList.push(pointData[1].seriesLabel);  
  
//instantiate a new array to hold data for this series  
pointSeries.push(new Array());  
}  
  
//Flot requires datetimes to be passed as timestamp values  
var pointDate = new Date(pointData[1].year, pointData[1].month-1, pointData[1].day);  
var timestamp = pointDate.getTime();  
  
//for each unique date value  
if(dateArray.indexOf(timestamp) == -1) {  
//add date timestamp to array of dates  
dateArray.push(timestamp);  
}  
  
//get the index of the series to which this particular value corresponds  
var seriesNumber = seriesList.indexOf(pointData[1].seriesLabel);  
  
//add this particular data value to the correct array in the point series array  
pointSeries[seriesNumber].push([timestamp, pointData[0]]);  
  
});  
  
//sort the unique dates so we can find the min and max dates later  
dateArray.sort(function(a,b){return a-b;});  
  
//we have a function that fills in missing dates with 0 values  
//so to make sure all series have the same set of data, we will add a dummy date to both ends of the range with 0 values  
//after we have &quot;filled out&quot; any missing values in the series, we will remove the dummy dates  
//get milliseconds per day so we can just add/subtract the value of the &quot;day&quot; variable later  
var minute = 1000 * 60;  
var hour = minute * 60;  
var day = hour * 24;  
  
//for each series  
for(var i=0; i&lt;seriesList.length; i++) {  
//the label we pass to Flot is the value from the series label array  
var seriesLabel = seriesList[i];  
  
//get a time series data variable from the correct array in the pointseries aray  
var tsData = pointSeries[i];  
  
//add a day with a 0 value to the beginning of the series  
tsData.push([dateArray[0]-day,0]);  
  
//add a day with a 0 value to the end of the series  
tsData.push([dateArray[dateArray.length-1]+day,0]);  
  
//sort the data points by date  
tsData.sort(function(a,b){return a[0]-b[0];});  
  
//fill in missing dates with 0-value points  
tsData = newDataArray(tsData);  
  
//remove the first &quot;dummy&quot; date  
tsData.shift();  
  
//remove the last &quot;dummy&quot; date  
tsData.pop();  
  
//create a new object to represent this series  
var seriesObj = new Object();  
  
//set a label property  
seriesObj.label = seriesLabel;  
  
//set a data property  
seriesObj.data = tsData;  
  
//add this object to the dataseries array that will be passed to Flot  
dataSeries.push(seriesObj);  
}  
  
//plot the data with some display options  
//see examples and API documentation at http://www.flotcharts.org/  
$.plot($(&quot;#chartdiv&quot;),   
dataSeries, {   
series: {  
lines: { show: true },  
points: { show: true }  
},   
grid: {   
hoverable: true ,  
markings: weekendAreas //calls the weekendAreas function to shade weekend days in gray  
},  
xaxis: {   
tickLength: 5,  
mode: &quot;time&quot;,  
timeformat: &quot;%m/%d/%y&quot;  
},  
yaxis: {  
tickDecimals: 0,  
min: 0  
}  
}  
);  
  
alert(&quot;Charting complete&quot;);  
}  
  
//this function is used to fill in the missing date values with 0 values  
//taken from http://stackoverflow.com/questions/14522667/how-to-configure-flot-to-draw-missing-time-series-on-y-axis-at-point-zero  
function newDataArray(data) {  
var startDay = data[0][0],  
newData = [data[0]];  
  
for (i = 1; i &lt; data.length; i++) {  
var diff = dateDiff(data[i - 1][0], data[i][0]);  
var startDate = new Date(data[i - 1][0]);  
if (diff &gt; 1) {  
for (j = 0; j &lt; diff - 1; j++) {  
var fillDate = new Date(startDate).setDate(startDate.getDate() + (j + 1));  
newData.push([fillDate, 0]);  
}  
}  
newData.push(data[i]);  
}  
return newData;  
}  
  
  
/* helper function to find date differences*/  
function dateDiff(d1, d2) {  
return Math.floor((d2 - d1) / (1000 * 60 * 60 * 24));  
}
</code></pre>
<p><strong>Format for the weekends</strong></p>
<p>The final difference from part I is calling a custom function to format the weekends on the chart. This is done in this part of the processData function above:</p>
<pre><code>grid: {   
hoverable: true ,  
markings: weekendAreas //calls the weekendAreas function to shade weekend days in gray  
},
</code></pre>
<p>The weekendAreas function:</p>
<pre><code>//helper for returning the weekends in a period  
//taken from http://www.flotcharts.org/flot/examples/visitors/index.html  
function weekendAreas(axes) {  
var markings = [];  
var d = new Date(axes.xaxis.min);  
// go to the first Saturday  
d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))  
d.setUTCSeconds(0);  
d.setUTCMinutes(0);  
d.setUTCHours(0);  
var i = d.getTime();  
do {  
// when we don't set yaxis, the rectangle automatically  
// extends to infinity upwards and downwards  
markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });  
i += 7 * 24 * 60 * 60 * 1000;  
} while (i &lt; axes.xaxis.max);  
  
return markings;  
}
</code></pre>
<p><strong>Trying it out</strong></p>
<p>Here is a complete web page with the code for you to download and try out in your own CRM instance <a href="https://alexanderdevelopment.net/content/images/2013/01/chart_example2.htm">chart_example2.htm (12.34 kb)</a>. Just upload it as you would any other web resource, publish and open.</p>
<p>When I run it in my CRM instance, this chart is generated.</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/contact_state_chart.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/contact_state_chart.PNG#img-thumbnail" alt="Generated chart"></a></p>
<p>As you can see, the chart gets a little busy, and it's hard to differentiate between the different series where they overlap, but there's a lot more you can do with Flot formatting options to make it look better. Also, I haven't covered everything Flot can do, so I encourage you to look at the Flot <a href="http://www.flotcharts.org/flot/examples/">examples page</a> to see some other possibilities like bar charts, stacked charts, panning/zooming, etc.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Better line charts in Dynamics CRM 2011 - part I]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Earlier this week I posted an <a href="https://alexanderdevelopment.net/post/2013/01/21/FetchXML-JQuery-in-a-Dynamics-CRM-2011-web-resource.aspx">entry</a> about using FetchXML and JQuery in a Dynamics CRM 2011 web resource. The reason I first started looking at those two together was that I wanted to see if I could generate better looking line charts than are available out of the box</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/01/23/better-line-charts-in-dynamics-crm-2011-part-i/</link><guid isPermaLink="false">5a5837216636a30001b97671</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[data visualizations]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Thu, 24 Jan 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Earlier this week I posted an <a href="https://alexanderdevelopment.net/post/2013/01/21/FetchXML-JQuery-in-a-Dynamics-CRM-2011-web-resource.aspx">entry</a> about using FetchXML and JQuery in a Dynamics CRM 2011 web resource. The reason I first started looking at those two together was that I wanted to see if I could generate better looking line charts than are available out of the box (spoiler alert: I did). In this post I will show how to combine FetchXML and JQuery with the <a href="http://www.flotcharts.org/">Flot</a> plotting library to produce line charts from CRM data aggregations.</p>
<p>In my career, one of the data visualizations I have encountered the most is to plot some value over unit time. For example, we can try to measure an agent's productivity by counting the number of phone calls per day. Because of the way Dynamics CRM stores data, if we restrict our queries to its database instead of a data warehouse, generally we can report on actions taken per unit time, but we can't report on how things change over time. We can say Agent X created 100 phone call records last week, but we can't tell how many overdue phone call records Agent X had in the queue yesterday. In my example here, I will show how to plot number of contacts created per day.</p>
<p><strong>Top of the page stuff</strong></p>
<p>Charting with Flot requires jQuery, Flot (obviously) and Excanvas in Internet Explorer. Here is how I pull those libraries in from CDNs, but if your CRM instance is accessed over a LAN, you should host them locally.</p>
<pre><code>&lt;!--[if lte IE 8]&gt;&lt;script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/flot/0.7/excanvas.min.js&quot;&gt;&lt;/script&gt;&lt;![endif]--&gt;  
&lt;script src=&quot;https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.0.min.js&quot;&gt;&lt;/script&gt;  
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/flot/0.7/jquery.flot.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>Also, Flot doesn't work so well in Internet Explorer quirks mode, so make sure you set the page to display in standards mode by declaring an HTML doctype like so in the first line: <!DOCTYPE html></p>
<p><strong>Writing the query</strong></p>
<p>As I explained previously, if you want to query aggregate data from inside JavaScript, you have to use FetchXML. While researching this topic, the examples I found weren't necessarily the clearest, but MSDN has a good overview <a href="http://msdn.microsoft.com/en-us/library/gg309565">here</a>.</p>
<p>Once you get the hang of the FetchXML syntax, if you can write your query in SQL group-by syntax, it shouldn't be too difficult to translate it to FetchXML. Here is the query we will use to count contacts by their createdon date:</p>
<pre><code>&lt;fetch distinct='false' mapping='logical' aggregate='true'&gt;  
&lt;entity name='contact'&gt;  
&lt;attribute name='fullname' alias='plotValue' aggregate='count' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='day' alias='day' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='month' alias='month' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='year' alias='year' /&gt;  
&lt;/entity&gt;  
&lt;/fetch&gt;
</code></pre>
<p>We have a single data field aliased as plotValue that is equivalent to SQL's count(fullname) as plotValue, and then there are three groupby fields that are based on the createdon field. They have each been given an alias that corresponds to the specific datepart.</p>
<p><strong>Executing the query</strong></p>
<p>To execute the FetchXML and retrieve the results, we will use the same basic technique I showed in my previous post.</p>
<ol>
<li>Get FetchXML query from a textarea field.</li>
<li>Build a SOAP message.</li>
<li>Send the SOAP message to CRM and register a callback function to process the data.</li>
</ol>
<p>To do this, we will use the same function executeFetchCommand, buildFetchRequest and sendQuery methods from my previous post. We will be using a different processData method, though the name will stay the same.</p>
<p><strong>Charting the data</strong></p>
<p>Once the data is returned by CRM, we can generate the chart. To do that, we will do the following:</p>
<ol start="2">
<li>Loop through XML to extract count for each date.</li>
<li>Convert the count and date values to an array of X and Y values for Flot to plot.</li>
<li>Call the Flot plotting method.</li>
<li>Bind an event to our chart to display tooltip messages that show the X and Y values when the user mouses over a specific point.</li>
</ol>
<p>First, our new processData callback function looks like this:</p>
<pre><code>function processData(xml) {  
/// &lt;summary&gt;  
/// charts data returned in a FetchXML response using Flot  
/// &lt;/summary&gt;  
  
alert(&quot;Charting started&quot;);  
  
//create a label for the chart points  
var yLabel = &quot;Contacts created&quot;;  
  
//create an array to hold the plot data  
var series1 = [];  
  
//loop through xml and extract data from each &quot;entity&quot; element  
$(&quot;#chartdiv&quot;).append(&quot;Starting XML parsing . . . &lt;br /&gt;&quot;);  
$(xml).find(&quot;a\\:Entity&quot;).each(function() {  
//pass the element to a function that extracts the aggregate value and the &quot;group by&quot; values  
//&quot;plotValue&quot; is the FetchXML alias for the data we want to display  
var pointData = getKeyValPairs($(this),&quot;plotValue&quot;);   
  
//Flot requires datetimes to be passed as timestamp values  
var dateString = (pointData[1].year + &quot;-&quot; + pointData[1].month + &quot;-&quot; + pointData[1].day).replace(/,/g,'');  
var timestamp = new Date(pointData[1].year.replace(/,/g,''), parseInt(pointData[1].month)-1, pointData[1].day).getTime();  
  
//add x (timestamp) and y (aggregate data value) values to the data series array  
series1.push([timestamp, pointData[0]]);  
});  
  
//sort series array by date - Flot plots in order, so line can look wrong if we don't do this  
series1.sort(function(a,b){return a[0]-b[0];});  
  
//plot the data with some display options  
//see examples and API documentation at http://www.flotcharts.org/  
$.plot($(&quot;#chartdiv&quot;),   
[ { data: series1, label: yLabel} ], {   
series: {  
lines: { show: true },  
points: { show: true }  
},   
grid: { hoverable: true },  
xaxis: {   
tickSize: [1, &quot;day&quot;],  
mode: &quot;time&quot;,  
timeformat: &quot;%m/%d/%y&quot;  
}  
}  
);  
  
alert(&quot;Charting complete&quot;);  
}
</code></pre>
<p>In this method first we loop through the data and pass each element to a getKeyValPairs helper function to extract the necessary fields. It returns an array with the Y value to plot as element 0 and a JSON object containing all other fields as element 1. It looks like this:</p>
<pre><code>function getKeyValPairs(entity, valuefield) {  
/// &lt;summary&gt;  
/// extracts an aggregate value and grouping components from a FetchXML response entity element and returns them in an array  
/// &lt;/summary&gt;  
var outputArray = new Array();  
  
//first get the aggregate value using its alias (&quot;plotValue&quot; in the original example)  
var pointValue = parseFloat(entity.find(&quot;a\\:KeyValuePairOfstringstring&quot;).filter(function() {  
return $(this).find('b\\:key').text() == valuefield;  
}).find(&quot;b\\:value&quot;).text().replace(/,/g,''));  
var groupingArray = [];  
entity.find(&quot;a\\:KeyValuePairOfstringstring&quot;).filter(function() {  
return $(this).find('b\\:key').text() != valuefield;  
}).each(function() {  
var xmlElement = $(this);  
var key = xmlElement.find(&quot;b\\:key&quot;).text();  
var value = xmlElement.find(&quot;b\\:value&quot;).text();  
var groupingText = '&quot;' + key + '&quot;:&quot;' + value + '&quot;';  
groupingArray.push(groupingText);  
});  
var stringToEval = groupingArray.join();  
var dateFields = eval(&quot;({&quot;+stringToEval+&quot;})&quot;);  
outputArray.push(pointValue);  
outputArray.push(dateFields);  
  
return outputArray;  
}
</code></pre>
<p>Once the data fields are returned by they getKeyValPairs method, the processData function creates a timestamp from the supplied month, day and year fields (Flot requires timestamps to plot by datetime), and then adds the timestamp and count to an array.</p>
<p>After the loop is complete, we sort the array by date to make sure the line will be plotted along our points in the correct order. Finally we call the Flot plot function with the data array and some pre-determined options. There are a lot of cool configuration options you can specify for Flot plots, but explaining them is beyond the scope of this point. Please take a look at the Flot <a href="http://people.iola.dk/olau/flot/examples/">examples</a> page for more.</p>
<p>Finally we need some code to do the tooltip display. First we have a generic showTooltip method that will be executed when the mouse moves over a data point. You can customize the style to your liking.</p>
<pre><code>function showTooltip(x, y, contents) {  
/// &lt;summary&gt;  
/// function to show tooltip when user mouses over data points  
/// &lt;/summary&gt;  
$('&lt;div id=&quot;tooltip&quot;&gt;' + contents + '&lt;/div&gt;').css( {  
position: 'absolute',  
display: 'none',  
top: y + 5,  
left: x + 5,  
border: '1px solid #fdd',  
padding: '2px',  
'background-color': '#fee',  
opacity: 0.80  
}).appendTo(&quot;body&quot;).fadeIn(200);  
}
</code></pre>
<p>Then we have code that binds a function to the chart plothover event so that the showTooltip method gets executed at the right time with the right data:</p>
<pre><code>//bind a function to execute the showTooltip function at the appropriate time  
var previousPoint = null;  
$(&quot;#chartdiv&quot;).bind(&quot;plothover&quot;, function (event, pos, item) {  
$(&quot;#x&quot;).text(pos.x.toFixed(2));  
$(&quot;#y&quot;).text(pos.y.toFixed(2));  
  
if (item) {  
if (previousPoint != item.dataIndex) {  
previousPoint = item.dataIndex;  
  
$(&quot;#tooltip&quot;).remove();  
var date = new Date(item.datapoint[0]);  
var x = item.datapoint[0].toFixed(2),  
y = item.datapoint[1];  
  
//call showTooltip with the timestamp converted back to mm/dd/yyyy format  
showTooltip(item.pageX, item.pageY,  
item.series.label + &quot; on &quot; + (parseInt(date.getMonth()+1)) + &quot;/&quot; + date.getDate() + &quot;/&quot; + date.getFullYear() + &quot; = &quot; + y);  
}  
}  
else {  
$(&quot;#tooltip&quot;).remove();  
previousPoint = null;   
}  
  
}); 
</code></pre>
<p><strong>Trying it out</strong></p>
<p>Here is a complete web page with the code for you to download and try out in your own CRM instance <a href="https://alexanderdevelopment.net/content/images/2013/01/chart_example.htm">chart_example.htm (8.30 kb)</a>. Just upload it as you would any other web resource, publish and open. At that point you will be presented with a screen that looks like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/chart_fetch_start.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/chart_fetch_start.PNG#img-thumbnail" alt="The FetchXML / JQuery / Flot example page"></a></p>
<p>Either leave the pre-populated FetchXML in the textarea or supply your own that does a count by month, day and year. As long as it returns those three group-by fields and a Y value aliased as &quot;plotValue,&quot; it should work. Once you click the &quot;fetch and process&quot; button, you will start to see some output and a couple of status alert windows before the output finally displays. The end result should look like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/chart_fetch_complete.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/chart_fetch_complete.PNG#img-thumbnail" alt="The FetchXML / JQuery / Flot example page"></a></p>
<p>Of course this chart is actually not that exciting, but once you take a closer look at how you can format the line chart output with Flot, you'll see there are all sorts of interesting things you can do. You can also embed the charts in dashboards as a replacement for the existing Dynamics CRM line chart controls. Stay tuned for my next post when I show how to generate multi-series charts.</p>
</div>]]></content:encoded></item><item><title><![CDATA[FetchXML + jQuery in a Dynamics CRM 2011 web resource]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Over the weekend I started looking at a hobby project that involved querying and working with aggregate data from Dynamics CRM 2011 inside a hosted web resource using jQuery. Initially had I planned to use the OData/REST endpoint since that is much sexier than SOAP lately, but after a</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/01/20/fetchxml-jquery-in-a-dynamics-crm-2011-web-resource/</link><guid isPermaLink="false">5a5837216636a30001b976b0</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[jQuery]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 21 Jan 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Over the weekend I started looking at a hobby project that involved querying and working with aggregate data from Dynamics CRM 2011 inside a hosted web resource using jQuery. Initially had I planned to use the OData/REST endpoint since that is much sexier than SOAP lately, but after a quick web search I realized that OData doesn't support &quot;group by&quot; queries, so that left me looking at FetchXML. As I mentioned in a post last month, I've generally avoided working with FetchXML, so I wasn't even sure where to get started to use it inside JavaScript. After another quick web search, I came across a great post on the Customer Effective blog called <a href="http://blog.customereffective.com/blog/2011/05/execute-fetch-from-javascript-in-crm-2011.html">Execute Fetch from JavaScript in CRM 2011</a>. That post shows a custom FetchUtil.js library that does three things:</p>
<ol>
<li>Create a properly formatted SOAP request for a FetchXML query</li>
<li>Execute the request using the XMLHttpRequest object</li>
<li>Return the XML response to the browser</li>
</ol>
<p>Using this original post to point me in the right direction, I combined the logic for creating the SOAP request with new jQuery code to handle the request and response. Here's how it works:</p>
<p><strong>Getting the FetchXML</strong></p>
<p>First we need to get the FetchXML to execute. For the purpose of this example, suppose we allow a user to execute ad-hoc FetchXML queries, so we need a method to read FetchXML from a textarea on a web page and then start processing. This method will be executed when a button is pushed:</p>
<pre><code>function executeFetchCommand() {   
/// &lt;summary&gt;  
/// reads user-supplied FetchXML contained in the txtFetch textarea and starts processing  
/// &lt;/summary&gt;  
  
//generate the SOAP envelope  
var fetchRequest = buildFetchRequest($(&quot;textarea#txtFetch&quot;).val());  
  
//send the request to CRM  
sendQuery(fetchRequest);  
}
</code></pre>
<p>The buildFetchRequest and sendQuery methods are described in the following sections.</p>
<p><strong>Generating the request</strong></p>
<p>First we need to generate the SOAP envelope from a FetchXML query. This method takes the query as an input parameter, properly encodes it and wraps it inside the envelope.</p>
<pre><code>function buildFetchRequest(fetch) {  
/// &lt;summary&gt;  
/// builds a properly formatted FetchXML request  
/// based on Paul Way's blog post &quot;Execute Fetch from JavaScript in CRM 2011&quot;  
/// http://blog.customereffective.com/blog/2011/05/execute-fetch-from-javascript-in-crm-2011.html  
/// &lt;/summary&gt;  
var request = &quot;&lt;s:Envelope xmlns:s=\&quot;http://schemas.xmlsoap.org/soap/envelope/\&quot;&gt;&quot;;  
request += &quot;&lt;s:Body&gt;&quot;;   
  
request += '&lt;Execute xmlns=&quot;http://schemas.microsoft.com/xrm/2011/Contracts/Services&quot;&gt;' +   
'&lt;request i:type=&quot;b:RetrieveMultipleRequest&quot; ' +   
' xmlns:b=&quot;http://schemas.microsoft.com/xrm/2011/Contracts&quot; ' +   
' xmlns:i=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;' +   
'&lt;b:Parameters xmlns:c=&quot;http://schemas.datacontract.org/2004/07/System.Collections.Generic&quot;&gt;' +   
'&lt;b:KeyValuePairOfstringanyType&gt;' +   
'&lt;c:key&gt;Query&lt;/c:key&gt;' +   
'&lt;c:value i:type=&quot;b:FetchExpression&quot;&gt;' +   
'&lt;b:Query&gt;';  
  
request += CrmEncodeDecode.CrmXmlEncode(fetch);   
  
request += '&lt;/b:Query&gt;' +   
'&lt;/c:value&gt;' +   
'&lt;/b:KeyValuePairOfstringanyType&gt;' +   
'&lt;/b:Parameters&gt;' +   
'&lt;b:RequestId i:nil=&quot;true&quot;/&gt;' +   
'&lt;b:RequestName&gt;RetrieveMultiple&lt;/b:RequestName&gt;' +   
'&lt;/request&gt;' +   
'&lt;/Execute&gt;';   
  
request += '&lt;/s:Body&gt;&lt;/s:Envelope&gt;';   
return request;  
}
</code></pre>
<p><strong>Executing the query</strong></p>
<p>Once you have the SOAP envelope ready, you need to send the request to your CRM server. This method takes the SOAP envelope generated in the previous step, makes an asynchronous call to the CRM 2011 organization service using the jQuery ajax method and registers a callback function to process the returned results. (It also writes some status info to an output region of a web page to make it easier for you to follow the code execution.)</p>
<pre><code>function sendQuery(fetchRequest) {  
/// &lt;summary&gt;  
/// uses jQuery ajax method to executes a FetchXML query and register a callback function  
/// &lt;/summary&gt;  
  
//path to CRM root  
var server = window.location.protocol + &quot;//&quot; + window.location.host;  
  
//full path to CRM organization service - you may need to modify this depending on your particular situation  
var path = server + &quot;/XRMServices/2011/Organization.svc/web&quot;;  
  
$(&quot;#outputdiv&quot;).append(&quot;Starting ajax request . . . &lt;br /&gt;&quot;);  
$.ajax({  
type: &quot;POST&quot;,  
dataType: &quot;xml&quot;,  
contentType: &quot;text/xml; charset=utf-8&quot;,  
processData: false,  
url: path,  
data: fetchRequest,  
beforeSend: function( xhr ){  
xhr.setRequestHeader( //without the SOAPAction header, CRM will return a 500 error  
&quot;SOAPAction&quot;,  
&quot;http://schemas.microsoft.com/xrm/2011/ Contracts/Services/IOrganizationService/Execute&quot; //remove the extra space inserted to help this line wrap  
);   
}  
}).done(function(data) {  
//if successful, pass returned xml and the plot label to the charting function  
processData(data);  
}).fail(function(jqXHR, textStatus, errorThrown ) {  
//if unsuccessful, generate an error alert message  
alert( &quot;Request failed: &quot; + textStatus + &quot;\n&quot; + errorThrown );  
});  
$(&quot;#outputdiv&quot;).append(&quot;Ajax request complete. Output will be processed asynchronously. &lt;br /&gt;&quot;);  
}
</code></pre>
<p>Here are a few things to note:</p>
<ol>
<li>The inside the &quot;done&quot; function is where we tell jQuery what to do when a successful response returns data. We will look at the processData method more closely in the next section.</li>
<li>The &quot;fail&quot; function generates an alert window with error output. You could do something more sophisticated.</li>
<li>You probably want to leave all the other ajax configuration options alone unless you have a good reason not to. It took a good bit of trial and error for me to get this right (probably because I was up too late at night working it out, but I digress . . . ).</li>
</ol>
<p><strong>Handling the response</strong></p>
<p>Assuming that everything went according to plan, our callback function will be called with the query results. At this point, you can do anything with them that you would normally do with XML inside of JavaScript. You can also convert the XML to JSON if that's more your speed. For demonstration purposes, I will show how to loop through the results and display the key-value pairs for each field returned.</p>
<p>Before I show the code to process the results, let's take a look at what the results would look like for this theoretical query:</p>
<pre><code>&lt;fetch distinct='false' mapping='logical' aggregate='true'&gt;  
&lt;entity name='contact'&gt;  
&lt;attribute name='fullname' alias='contact_count' aggregate='count' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='day' alias='day' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='month' alias='month' /&gt;  
&lt;attribute name='createdon' groupby='true' dategrouping='year' alias='year' /&gt;  
&lt;/entity&gt;  
&lt;/fetch&gt;
</code></pre>
<p>In this query I am counting the number of contacts created by day, month and year. When I execute it against CRM, I get output that looks like the contents of the attached file: <a href="https://alexanderdevelopment.net/content/images/2013/01/response.xml">response.xml (6.76 kb)</a>  Here are some important points:</p>
<ol>
<li>Each row of data is represented as an &quot;a:Entity&quot; element.</li>
<li>Individual attribute names and values can be found in the an entity's &quot;a:Attributes&quot; element and also in its &quot;a:FormattedValues&quot; element. In this example I will be working with the &quot;a:FormattedValues&quot; element because it's marginally easier to parse, however you may find times that it makes more sense to work with &quot;a:Attributes&quot; instead.</li>
<li>Everything under &quot;a:FormattedValues&quot; is represented as a string, so we would need to convert to other datatypes where necessary (ie. building a date object from the returned month / day / year values).</li>
<li>Each key-value pair under &quot;a:FormattedValues&quot; is contained in an &quot;a:KeyValuePairOfstringstring&quot; element.</li>
</ol>
<p>Now that you know what the response from CRM looks like, here is the method that parses it and writes the output:</p>
<pre><code>function processData(xml) {  
/// &lt;summary&gt;  
/// writes key-value pairs to a div  
/// &lt;/summary&gt;  
  
alert(&quot;Output started&quot;);  
$(&quot;#outputdiv&quot;).append(&quot;OUTPUT FROM CRM &lt;br /&gt;&quot;);  
  
//outer loop  
$(xml).find(&quot;a\\:Entity&quot;).each(function() {  
//write entity  
$(&quot;#outputdiv&quot;).append(&quot;Entity &lt;br /&gt;&quot;);  
//inner loop  
$(this).find(&quot;a\\:KeyValuePairOfstringstring&quot;).each(function() {  
var xmlElement = $(this);  
var key = xmlElement.find(&quot;b\\:key&quot;).text();  
var value = xmlElement.find(&quot;b\\:value&quot;).text();  
$(&quot;#outputdiv&quot;).append(&quot;  Key: &quot; + key + &quot; Value: &quot; + value + &quot;&lt;br /&gt;&quot;);  
  
});  
});  
  
alert(&quot;Output complete&quot;);  
}
</code></pre>
<p>You'll see there are two loops that use the jQuery find method. First the outer loop finds each a:Entity element, and then it passes that element to another function that executes the inner loop to find each a:KeyValuePairOfstringstring element. Then that element is passed to another function that extracts the text of the &quot;b:key&quot; and and &quot;b:value&quot; elements and writes them to the web page output div using jQuery's append method.</p>
<p><strong>Trying it out</strong></p>
<p>Here is a complete web page with the code for you to download and try out in your own CRM instance: <a href="https://alexanderdevelopment.net/content/images/2013/01/jquery_fetchxml.htm">jquery_fetchxml.htm (4.53 kb)</a>. Just upload it as you would any other web resource, publish and open. At that point you will be presented with a screen that looks like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/fetch_start.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/fetch_start.PNG#img-thumbnail" alt="The FetchXML / JQuery example page"></a></p>
<p>Either leave the pre-populated FetchXML in the textarea or supply your own. Once you click the &quot;fetch and process&quot; button, you will start to see some output and a couple of status alert windows before the output finally displays. The end result should look like this:</p>
<p><a href="https://alexanderdevelopment.net/content/images/2013/01/fetch_complete.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/fetch_complete.PNG#img-thumbnail" alt="The FetchXML / JQuery example page showing output"></a></p>
<p>As mentioned earlier, the attribute values retrieved are all strings, so you'll see the years have commas in them (2,013 instead of 2013). The solution is to either get the integer value from the XML response or parse the text value into an integer.</p>
<p>Caveats:</p>
<ol>
<li>In the demo web page, I am using the jQuery library hosted by the Microsoft Ajax Content Delivery Network. If your users are accessing a CRM instance on your LAN, it would be better to host the jQuery library inside of CRM.</li>
<li>I don't know how this page hosted as a web resource will work in browsers other than Internet Explorer. Initially I did most of the jQuery prototyping work with a locally stored XML file on my PC using Chrome, and that code didn't work in IE without a lot of changes. Particularly noteworthy is that Chrome could find the XML elements without me needing to specify a namespace (&quot;a:&quot; or &quot;b:&quot;), but IE wouldn't. I did not go back and test whether the modified find selectors worked in Chrome.</li>
</ol>
</div>]]></content:encoded></item></channel></rss>