Tag Archives: jQuery

SAMPLE: Editable grid for CRM 2011 using jqGrid

A while back, I wrote a post called Building an editable grid for CRM 2011.   The goal of the post was to give you the necessary knowledge to know how to write the code to build an editable grid.  Since then, someone introduced me to jqGrid.  This is quite a powerful JavaScript grid control.  Have a look at the site to see all the things you can do with it.

I’ve built a little sample for a customer using jqGrid.  I wanted to spend some time cleaning the code up and making it more reusable before I blogged about it.  My lofty goal was for it to be a fully reusable editable grid control for CRM.  My thinking was that all you would have to do is drop a web resource on the form, pass the web resource a set of parameters (child entity, columns to display, etc.), and the web resource would render a custom grid based on what you passed it.  Well, as most of my lofty goals for side projects go, I haven’t found the time to get it where I want it to be.  Since then I’ve promised a number of folks to at least share what I have until I can get around to turning this into what I want it to be. 

To get started, download the sample from here.  Unzip the contents somewhere.  If you want to open the Visual Studio solution, you will need the Developer Toolkit for Microsoft Dynamics CRM installed.   Make sure you read the README.txt file in the root of the CrmEditableGrid project.  As I say in the readme:

THIS IS NOT A FULLY REUSABLE EDITABLE GRID CONTROL.  IT IS A SAMPLE DEMONSTRATING HOW
TO USE THE FACILITIES OF THE CRM 2011 SDK COMBINED WITH A POPULAR JAVASCRIPT GRID CONTROL (jqGrid).
WITH THIS AS YOUR STARTING POINT, YOU SHOULD BE ABLE TO USE THE CRM 2011 SDK AND THE jqGrid
DOCUMENTATION TO ADD ADDITIONAL CAPABILITIES TO THE GRID SUCH AS: ADD/DELETE ROW, OPTION SETS, ETC.

To get the sample working, import the dkdteditablegrid.zip file into your CRM organization.  It’s an unmanaged solution.  Make sure you publish all customizations at the end of the import.  I didn’t export the sitemap so you will need to find the Parent entity and add it to the Workplace area to see it:

image

Make sure you publish and refresh the browser so the updates show up.  Ok, I warned you that this sample was incomplete.  To get the editable grid into a useable state, you need to create a Parent record and a couple related Child records.  Navigate to Workplace->Extensions->Parents and create a new parent.  Make sure you Save (not Save & Close).

image

Now navigate to Related->Common->Children and add a couple children.

image

Once you’ve added a couple children.  Close the form and open it again.  Like I said, work in progress.  What you’ll see is a grid on the form that looks something like this:

image

If you click the “e” button, then you’ll put the record in edit mode.  The “c” button cancels and the “s” button saves the record.  The way this works is as follows:

  • The grid is an html web resource that is passed the record id from the parent form
  • When the web resource loads, it makes an OData query for the children
  • Upon query completion, it wires up the data to the jqGrid
  • When “s” button is clicked, the code updates the child record through the OData service

The goal of this sample, for now, is to have enough of the core plumbing in place for you to take and elaborate to your specific scenario.  Once you realize how capable jqGrid is, then you’ll understand that it’s not that big of a leap forward to get to where you want to be.  I still plan to transform this from a code sample to something people can just pickup and use on many forms by passing a few parameters to the web resource.  Of course, time needs to be on my side…yes it does.  Let me know if you beat me to it! 

@devkeydet

Displaying a lookup as a dropdown in a CRM 2011 form

UPDATE (04JUN2013):  If you need to evolve this sample to support a one to many relationship represented as a multi-select, I like this multi-select control which can be themed with jQuery UI themes.

Another scenario from a customer:

We want to use a lookup to another entity because we want to store additional data in the  entities fields and option sets don’t provide this capability.  However, we want the selection of the entity in the form to be a dropdown to minimize the # of clicks a user must go through to select the entity.

HTML / JavaScript web resources and the OData service to the rescue!  First, this sample was loosely inspired by this post from my teammate Carlton Colter.  I took his idea, ran with it, applied it to this problem, and made my solution a reusable web resource that you can pass parameters to in order to apply it to any lookup on a form.  Here are the steps…

Add the lookup field to the form:

image

Notice that this lookup is required.  This solution respects the required metadata of the field and uses it to ensure the dropdown has a value before the form is saved.  Set the properties of the lookup making sure the Visible by default option is unchecked:

image

Insert an html web resource to the form with the following General settings configured (the code for the web resource is available further down):

image

The Custom Parameter(data) property is what makes this reusable.  You can figure out what needs to be passed in by looking at the JavaScript, but here is the comma separated format:

lookupEntitySetName,lookupEntityIdFieldName,lookupEntityDisplayFieldName,nameOfLookupFieldOnForm,webResourceName

Here is a longer description if the variable names aren’t clear enough:

lookupEntitySetName = Name of the entity set in the OData service for the entity.

lookupEntityIdFieldName = The id/primary key for the in the OData service.

lookupEntityDisplayFieldName = The field name from the entity that you want to display in the dropdown.

nameOfLookupFieldOnForm = The name of the actual lookup field that is hidden on the form.

webResourceName = The name of the web resource on the form.  This is set in the Add Web Resource dialog and always starts with WebResource_.

Make sure you set the properties on the Formatting tab like so:

image

Finally, there is a little bug that I gave up on.  So you will need to put a spacer next to or below the web resource:

image

This will prevent the dropdown for getting cut off if there is nothing to the right or bottom of it.  If it already has something to the right of it or below it, then this is unnecessary.  Bingo bango!  You now have a lookup that’s represented on the form as a dropdown complete with required validation:

image 

The dropdown is just UI trickery.  When you save the form, the value of the lookup is saved correctly.  In update scenarios, the form loads, reads the hidden lookup value, and sets the dropdown selected item appropriately.

Here’s the code for the html web resource:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

    <head>

        <title></title>

        <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>

        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js" type="text/javascript"/>

        <script src="scripts/dropdownforlookup.htm.js" type="text/javascript"/>

 

        <!-- TOOD: move the needed styles into our own stylesheet. The CRM team doesn't support referencing their styles because they can change -->

        <link href="/_common/styles/fonts.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/global.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/select.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

    </head>

    <body style="background-color: rgb(246, 248, 250); border-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-top: 0px;">

        <!-- TOOD: move the needed styles into our own stylesheet. The CRM team doesn't support referencing their style sheets because they can change -->

        <select id="lookupdropdown" class="ms-crm-SelectBox">

            <option value="Loading..." selected="selected">Loading...</option>

        </select>

    </body>

</html>

Here’s the code for the dropdown.htm.js file that it references:

$(document).ready(function () {

    var context = GetGlobalContext();

    var params = context.getQueryStringParameters();

    // The data passed to the web resource should be in the following format:

    //

    // lookupEntityName,lookupEntityIdFieldName,lookupEntityDisplayFieldName,nameOfLookupFieldOnForm,webResourceName

    //

    var dataParam = params.data.split(",");

    var lookupEntitySetName = dataParam[0];

    var lookupEntityIdFieldName = dataParam[1];

    var lookupEntityDisplayFieldName = dataParam[2];

    var nameOfLookupFieldOnForm = dataParam[3];

    var webResourceName = dataParam[4];

 

    var oDataQuery = context.getServerUrl() + "/XRMServices/2011/OrganizationData.svc" +

    "/" + lookupEntitySetName + "?$select=" + lookupEntityIdFieldName + "," + lookupEntityDisplayFieldName;

 

    var lookupAttribute = window.parent.Xrm.Page.getAttribute(nameOfLookupFieldOnForm);

    var lookupArray = lookupAttribute.getValue();

 

    $.getJSON(oDataQuery, function (data) {

        var results = data.d.results;

        var lookupdropdown = $("#lookupdropdown");

 

        for (var i = 0; i < results.length; i++) {

            var option = "<option value='" + results[i][lookupEntityIdFieldName];

            option += "'>" + results[i][lookupEntityDisplayFieldName] + "</option>";

            lookupdropdown.append(option);

        }

 

        lookupdropdown.prepend("<option value='blank'></option>");

 

        if (lookupArray) {

            var lookupId = lookupArray[0].id.replace("{", "").replace("}", "").toLowerCase();

            lookupdropdown.val(lookupId);

        } else {

            lookupdropdown.val("blank");

        }

 

        $("#lookupdropdown option[value='Loading...']").remove();

 

        lookupdropdown.width("100%"); // couldn't figure out what was causing it to not stretch so I just forced it

 

        lookupdropdown.change(function () {

            var name = $("#lookupdropdown option:selected").text();

            if (name == "") {

                SetLookupValueToNull(nameOfLookupFieldOnForm);

            } else {

                var entityType = results[0].__metadata.type.replace("Microsoft.Crm.Sdk.Data.Services.", "");

                SetLookupValue(nameOfLookupFieldOnForm, lookupdropdown.val(),

                name, entityType);

            }

        });

    });

 

    var requiredLevel = lookupAttribute.getRequiredLevel();

 

    if (requiredLevel == "required") {

        // We want to drive whether our dropdown requires a value by the hidden lookup fields metadata

        // However, if we keep the lookup field's requirement level to required the form validation

        // will tell us it is required an force us to show it.

        lookupAttribute.setRequiredLevel("none");

 

        //NOTE: Modifying html that the CRM server sends down to the browser is not supported.

        // However, here we are finding a label for this control and updating its text.

        // This is relatively harmless and the likelihood of the CRM representing a label

        // for a control as anything other than an html label control is low. So I feel safe

        // enough to break the "don't touch the CRM html" rule. Even if it becomes an issue

        // at upgrade, we have one place where we can make the adjustments

        var label = $("label[for='" + webResourceName + "']", window.parent.document);

 

        // TODO: Improve this so it isn't tightly coupled to CRM generated html/css. Using undocumented css and server urls is unsupported.

        label.append("<IMG class=ms-crm-ImageStrip-frm_required alt=Required src='/_imgs/imagestrips/transparent_spacer.gif?ver=600790655'>");

 

        // TODO: add onsave to display an error message.

        window.parent.Xrm.Page.data.entity.addOnSave(function (context) {

            var name = $("#lookupdropdown option:selected").text();

            if (name == "") {

                var labelForWebResource = window.parent.Xrm.Page.getControl(webResourceName).getLabel();

                alert("You must provide a value for " + labelForWebResource + ".");

                context.getEventArgs().preventDefault();

            }

        });

    }

});

 

function SetLookupValue(fieldName, id, name, entityType) {

    if (fieldName != null) {

        var lookupValue = new Array();

        lookupValue[0] = new Object();

        lookupValue[0].id = id;

        lookupValue[0].name = name;

        lookupValue[0].entityType = entityType;

 

        window.parent.Xrm.Page.getAttribute(fieldName).setValue(lookupValue);

    }

}

 

function SetLookupValueToNull(fieldName) {

    if (fieldName != null) {

        window.parent.Xrm.Page.getAttribute(fieldName).setValue(null);

    }

}

@devkeydet

Showing a jQuery UI dialog in a CRM 2011 form

I was asked how to implement the following scenario in a CRM 2011 form (paraphrased):

  • Show an alert notification indicator in the header
  • When the user to click the notification indicator, show a dialog with the details of the alert

Here’s how I did it.  The code below assumes you’ve already wired up jQuery and jQuery UI to the form.

Add an html web resource to the header:

image

Configure the web resource properties:

imageimage

Here’s the markup for the html web resource:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

    <head>

        <title></title>

        <script src="../ClientGlobalContext.js.aspx" type="text/javascript"/>

        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js" type="text/javascript"/>

        <script src="scripts/dialogfromheader.htm.js" type="text/javascript"/>

        

        <!-- TODO: move the needed styles into our own stylesheet.  The CRM team doesn't support referencing their styles because they can change -->

        <link href="/_common/styles/fonts.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/global.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/select.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

    </head>

    <!-- TODO: move the style info into our own stylesheet. -->

    <body style="background-color: rgb(246, 248, 250); border-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-top: 0px;">

        <img id="alert" src="images/alert_icon_red.jpg" alt="alert icon"

             width="25px" height="25px" style="cursor:pointer"/>

    </body>

</html>

Here’s the code for the referenced dialogfromheader.htm.js script file:

$(document).ready(function () {

    // Execute an OData ajax query to determine if there are alert records (stored in a related entity)

    // You probably need to pass entity id to the page from the CRM form to compose a proper query

    // If alerts exist show the alert UI, otherwise do nothing

    // I am not doing that here, but it should be obvious enough

 

    // If you have results, build up the html to put in the dialog to represent the alerts information

    var htmlForTheDialog = "<p>PLACED HOLDER FOR THE ALERT HTML</p>";

 

    $("#alert").click(function() {

        window.parent.dkdt_showDialog(htmlForTheDialog);

    });

});

Add a JavaScript web resource to the form:

image

Here’s the code for the referenced dialogsetup.js script file:

function dkdt_wireupDialog() {

    // NOTE: This clearly deviates from the 

    // "don't touch the HTML generated by the CRM UI" guidance from the SDK

    // Typically, I urge people not to do this because it is technically unsupported.

    // However, in this case we're not really modifying the generated UI.

    // We are just adding a div to the body of the html.

    // I'm accepting that I am doing something that's unsupported, but still relatively low risk of side effects

    $("body").append("
"
);

    $("#dkdt_dialog").dialog({ autoOpen: false, position: "top" });

}

 

function dkdt_showDialog(dialogHtml) {

    $("#dkdt_dialog").html(dialogHtml);

    $("#dkdt_dialog").dialog("open");

}

Now, when an end user clicks on the alert icon they will see the alert details:

image

@devkeydet

OQuery – A fluent API to build OData url queries sans LINQ

Yesterday, I blogged about a solution to compose OData / WCF Data Service queries using LINQ for situations where LINQ enabled client libraries don’t exist (i.e. JavaScript and Windows Phone 7).

http://blogs.msdn.com/b/devkeydet/archive/2011/02/02/data-services-odata-client-for-windows-phone-7-and-linq.aspx

The post is all about using LINQPad as a tool to write your LINQ queries, then using the feature in LINQPad that gives you the url query translation.  Well today, a new MSDN Code Callery project just popped up called OQuery that offers another approach that doesn’t require using an external tool such as LINQPad:

http://code.msdn.microsoft.com/oquery

Here’s the description from the project page:

“OQuery is a library which gives you a fluent style interface for building OData Url Fragments in javascript or C#.
Neither Javascript or Silverlight for WP7 support LINQ and so this library in those cases.”

What are you waiting for?  Go check it out!

Follow devkeydet on Twitter

The unofficial biography of Microsoft, ASP.NET, Ajax, and jQuery

The Microsoft Ajax strategy has been a bit of a winding road.  Even if you’ve kept up with the evolution, as I have, you might be a little confused.  Today, Scott Guthrie published a blog post announcing that Microsoft’s first submissions to jQuery are official.  There was a corresponding blog post on the jQuery blog.  There’s also an overview video about the Microsoft submissions by Stephen Walther over on Ch.9.  What’s not covered in these posts is the historical evolution that brings us to what was announced today.  You may may be saying to yourself “So what?”  Well, the internet is full of blog posts on the topic.  Depending on the place in time when the blog post or article you come across via your favorite search engine (Bing of course) was published, you might be led astray.  Knowing what’s what and the history helps you from making the mistake of following stale information.  Dave Ward to the rescue!  He wrote up what I think if as the “unofficial biography” on the topic.  Definitely worth a read:

Javascript Libraries and ASP.NET: A Guide to jQuery, AJAX and Microsoft

Does jQuery ship with SharePoint 2010? (and why you should be using an Ajax CDN)

jQuery is one of the most popular javascript libraries used by ASP.NET developers.  In fact, jQuery ships with Visual Studio 2010.  It is in the “Scripts” folder of a new “ASP.NET Web Application” or “ASP.NET MVC 2 Web Application” project template.

Does jQuery ship with SharePoint 2010?  Short answer: No.  I see this asked (publicly and internally) a few times a month.  Long answer: You don’t need it to.  Just use it from the Microsoft Ajax CDN

Assuming you don’t have to build a solution on a closed network with no internet access, then one of the first things you should consider is to replace all the references in your code to local javascript files to CDN references.  By doing so you get the general benefit that all CDNs offer (not just Ajax CDNs) which is that you get directed to a server the is closer to you.  Also, since browsers cache files based on URL, referencing the CDN from all your code means that different web apps use the same version of the javascript file cached in the browser.  Last, but not least, it means less files you have to maintain on your own servers.

Here’s what a script reference to jQuery 1.4.2 looks like when it is local:

<script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>

Here’s what it looks like when referencing the CDN:

<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>

So that’s how easy it is to reference jQuery from your SharePoint code.  However, as you can see, this applies way beyond just SharePoint programming.