<?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[OData - Alexander Development]]></title><description><![CDATA[OData - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>OData - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Fri, 24 Apr 2026 14:19:32 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/odata/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><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[Dynamically setting field requiredlevel attributes in Dynamics CRM 2011]]></title><description><![CDATA[<div class="kg-card-markdown"><p>One of the things I like best about the Dynamics CRM 2011 form object model is that it exposes the requiredlevel attribute for form fields, so you can dynamically set fields as required or not in response to user actions. This is great if you have different types of a</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/01/15/dynamically-setting-field-requiredlevel-attributes-in-dynamics-crm-2011/</link><guid isPermaLink="false">5a5837216636a30001b97679</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[OData]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Wed, 16 Jan 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>One of the things I like best about the Dynamics CRM 2011 form object model is that it exposes the requiredlevel attribute for form fields, so you can dynamically set fields as required or not in response to user actions. This is great if you have different types of a single entity and business rules dictate that you must capture different data values for each type. For example, let's say you use the out-of-the-box Contact entity to represent two kinds of customers, small and large. For the small customers, your agents need to always fill in a customer loyalty code field, but for the large customers this field will never be populated. In the absence of a way to dynamically set the required level, you have two choices:</p>
<ol>
<li>Make the field required at the Contact entity level and train your agents to type in something like &quot;not applicable&quot; or &quot;N/A&quot; for large customers. This, of course, fills up your database with garbage values.</li>
<li>Make the field optional, but train your agents to always populate it for small customers. This approach is even worse. While you can report on agent compliance retrospectively, you will almost assuredly end up with incomplete data for some records.</li>
</ol>
<p>In this post, I will show how to use JavaScript to set the requiredlevel attribute of a field based on two separate conditions:</p>
<ol>
<li>The value of another field on the form</li>
<li>The value of a field on a related entity (think a Contact's parent Account record)</li>
</ol>
<p><strong>Same-entity dynamic requiredlevel condition</strong></p>
<p>The following method handles a silly scenario in which we need to check if a Contact's middlename field is populated, and if so, set the telephone1 field requiredlevel to required. If not, the requiredlevel of telephone1 will be set to none.</p>
<pre><code>function SetRequiredSameEntity() {  
var middlename = Xrm.Page.getAttribute(&quot;middlename&quot;).getValue(); //get the middlename value  
if(middlename!=null)  
{  
Xrm.Page.getAttribute(&quot;telephone1&quot;).setRequiredLevel(&quot;required&quot;); //set required  
}  
else  
{  
Xrm.Page.getAttribute(&quot;telephone1&quot;).setRequiredLevel(&quot;none&quot;); //set none  
}  
}
</code></pre>
<p>To enable this functionality, do the following:</p>
<ol>
<li>Create a new Jscript web resource that contains the SetRequredSameEntity method. I call mine, somewhat creatively I think, firstlibrary (new_firstlibrary).</li>
<li>Open the contact form designer.</li>
<li>Open the form properties.</li>
<li>Add the firstlibrary library to the form.<a href="https://alexanderdevelopment.net/content/images/2013/01/add_library.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/add_library.PNG#img-thumbnail" alt="Adding a library to the form"></a></li>
<li>Add the SetRequiredSameEntity method to be called as part of the form OnLoad event. This is required so that the field is set to required if it already has a middlename populated when it loads. Make sure you enable the method, and you can, optionally, set dependencies so that the fields this method uses will not be removable from the form. <a href="https://alexanderdevelopment.net/content/images/2013/01/add_method.PNG#img-thumbnail"><img src="https://alexanderdevelopment.net/content/images/2013/01/add_method.PNG#img-thumbnail" alt="Addinga method to an event"></a></li>
<li>Close the form properties.</li>
<li>Double-click on the middlename field to open its property window. Go to the events tab and add the SetRequiredSameEntity method to be called as part of the field OnChange event just like in step 5.</li>
<li>Close the field properties.</li>
<li>Save your form changes and publish your customizations.</li>
<li>Open an existing contact record or create a new one to see the changes in action.</li>
</ol>
<p><strong>Related-entity dynamic requiredlevel condition</strong></p>
<p>The following code handles a scenario in which telephone1 should be required for Contacts linked to a parent Account with an accountnumber value of 1234. Otherwise, telephone1 is not required. Unlike previously where the data was already available to us from the current form, in this method we will need to execute an OData query to retrieve the accountnumber value for evaluation.</p>
<pre><code>function SetRequiredFromParentAccount() {  
//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;;  
  
//default telephone1 requiredlevel to &quot;none&quot;  
Xrm.Page.getAttribute(&quot;telephone1&quot;).setRequiredLevel(&quot;none&quot;);  
  
//get the parent account lookup  
var parentaccount = Xrm.Page.getAttribute(&quot;parentcustomerid&quot;).getValue();  
  
//if it's not null  
if(parentaccount != null)  
{  
//extract the id  
var parentaccountid = parentaccount[0].id;  
  
//set up the odata query  
var retrieveReq = new XMLHttpRequest();  
var odataQuery = odataPath + &quot;/AccountSet?$select=AccountNumber&amp;$filter=AccountId eq guid'&quot; + parentaccountid + &quot;'&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 () { SetRequired(this); };  
  
//send the request  
retrieveReq.send();  
}  
}  
  
//callback function to parse the response and react accordingly  
function SetRequired(retrieveReq) {  
//4 means a complete response  
if (retrieveReq.readyState == 4) {   
//parse response to json  
var retrieved = this.parent.JSON.parse(retrieveReq.responseText).d;   
  
//get the accountnumber value - CASE MATTERS!  
accountnumber = retrieved.results[0].AccountNumber;   
  
//if the accountnumber is 1234  
if(accountnumber==&quot;1234&quot;)   
{  
//set the required level  
Xrm.Page.getAttribute(&quot;telephone1&quot;).setRequiredLevel(&quot;required&quot;);   
}  
};  
}
</code></pre>
<p>In this scenario we use two methods instead of one because the OData retrieve executes asynchronously, and we need a callback function to process the results whenever they come back. Beyond making sure you use the correct casing in your OData query and where you get the accountnumber out of the returned JSON object, it's basically standard JavaScript like before.</p>
<p>To enable this functionality, do the following:</p>
<ol>
<li>Set the value of the odataPath variable to your Organization Rest Service URL under Customizations-&gt;Developer Resources.</li>
<li>Add these new methods to your script library.</li>
<li>Open the contact form designer.</li>
<li>Open the form properties.</li>
<li>Add the firstlibrary library to the form if it's not already there from the previous example.</li>
<li>Remove the SetRequiredSameEntity method to be called as part of the form OnLoad event, if it's already there. Add the SetRequiredFromParentAccount method to the form OnLoad event.</li>
<li>Close the form properties.</li>
<li>Double-click on the middlename field to open its property window. Go to the events tab and remove the SetRequiredSameEntity method if it's already there. Add the SetRequiredFromParentAccount just like before.</li>
<li>Close the field properties.</li>
<li>Save your form changes and publish your customizations.</li>
<li>Open an existing contact record or create a new one to see the changes in action.</li>
</ol>
<p>Here is the code for the complete library: <a href="https://alexanderdevelopment.net/content/images/2013/01/new_firstlibrary.js">new_firstlibrary.js (2.02 kb)</a></p>
</div>]]></content:encoded></item></channel></rss>