Setting a CRM 4.0 Lookup field in JavaScript – part deux

Yes, some time has passed since I last posted a blog article and yes, I could say that it won’t happen again but I don’t want to make any promises. Since my last post a lot of things have changed in my life, so my apologies. That said, we aren’t here to discuss me. We’re all about the CRM. If I can keep my focus I would expect many new blogs posts about CRM 2011 as well as some CRM 4.0 blog posts that I’ve been meaning to get out the door. For this post however I just wanted to drop a little something for everyone, so here goes.

You may recall that I had previously posted and explained how to set the value of a Lookup field in CRM 4.0. Well, I’m going to quickly show how to take that to the next level to keep your life (actually, your code) clean and concise.

First, let me post a refresher of the SDK code to set the value of a Lookup field:

var lookupObject = new Object;
var  lookupObjectArray = new Array();
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;
crmForm.all.new_userid.ForceSubmit = true;

Now that code comes from the SDK, and is intended to allow people to follow along and understand what’s happening. Long story short, there’s another notation called JSON (JavaScript Object Notation)

json Read more about JSON by visiting http://JSON.org

I won’t waste your time explaining what the JSON site can explain to you, but we can shorten our code by using JavaScript Object Notation. I’ll post the same code block getting smaller each time so that you can see what I’m doing. First, you don’t have to use the “new Array()” syntax to create an array. In fact, many JavaScript gurus recommend against it. Instead, you can simply use the square brackets, like this:

var lookupObject = new Object;
var  lookupObjectArray = [];
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;

JavaScript also allows to use the curly braces to declare an object, as shown here:

var lookupObject = {};
var  lookupObjectArray = [];
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;

Looking at the code like this may make you consider whether we actually need the lookupObjectArray variable at all, and in fact we don’t. We could simply do this:

var lookupObject = {};
lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
crmForm.all.new_userid.DataValue = [lookupObject];

Now to use JSON, we can declare our object in one statement. All you C# folks may find that it looks a lot like automatic initializers. Here goes:

var lookupObject = {
        id: "21EC2020-3AEA-1069-A2DD-08002B30309D",
        name: "John Doe",
        typename = "systemuser"
    };
crmForm.all.new_userid.DataValue =  [lookupObject];

Finally, if we got this far you may have guessed that we don’t really need lookupObject and we can instead simply declare it inline, like this:

crmForm.all.new_userid.DataValue = [{
        id:  "21EC2020-3AEA-1069-A2DD-08002B30309D",
        name: "John Doe",
        typename =  "systemuser"
    }];

There we have it. Doesn’t that look more clean and concise than what we started with? I think so, and I hope you do too. Cheers!

Improving readability of disabled fields in CRM 4.0

In talking with others apparently this is a common item that people ask for, and I finally ran across it so I figured it would be best to document my approach.

Background:
So we really do some neat things to push the envelope with CRM and this case was no exception. I will dispense with the gory details but long story short we were retreiving some data from an external source (using jQuery, Ajax, and JSON from a WCF service – how cool is that?) on a CRM form and we wanted the fields to be disabled once the field’s data was populated.

Sounds simple enough right? It could have been as simple as this:

crmForm.all.fieldname.value = "foo";
crmForm.all.fieldname.Disabled = true;

It could have been that simple and it was until our users wanted to look at the results. Enter problem stage left.

It appears that I’ve been given the gift of normal vision but not all the users had. It turns out that when you set the Disabled property to true on a CRM field one of the things it does is to change the field’s background and its border to muted color which signifies that the field is disabled. The users were fine with that. The other thing it can do is change the text color of the field to gray. Here’s an example:

This isn’t so good when your users want to read the contents and don’t have perfect vision. Trust me, we even have to scale back our minimum resolution requirements so that all the users can see.

The request was to keep the text color black and just have the background change. So how did I accomplish this?

It really only took a couple of steps. First, I wanted to make sure that the field was still effectively disabled so that the users couldn’t change the data on the field. Since CRM is an Internet Explorer only application, the issue was that when IE sees that a field is disabled it decides to be nice and change the text color to gray. Instead there is another property that you can use called readonly. Setting a field’s readonly property to true does in fact prevent the user from changing the value, so there’s our first part of the problem solved. You can make a field readonly in JavaScript like this:

crmForm.all.fieldname.readOnly = true;

The problem is that we didn’t wanted to leave it like that because when you make a field readonly it looks like this:

That’s functionaly fine, but as you can see it does give the user the impression that they can still edit it. So, let’s make them think it’s disabled by changing the background color, like this:

crmForm.all.fieldname.style.backgroundColor = "#eaf3ff";

Doing so produces the following result:

Alright, we’re almost there. For any perfectionists out there you may notice 2 differences from the first image:

1. The text is black, not gray, which is what we’re going for.
2. The border color is different.

So, we can quickly fix that by setting the border color using a little JavaScript too:

crmForm.all.fieldname.style.borderColor = "#c5c5c5";

Taking one last look we see that the results are exactly what we wanted:

So, in summary, 3 lines of JavaScript gets you exactly where you wanted to be:

crmForm.all.fieldname.readOnly = true;
crmForm.all.fieldname.style.backgroundColor = "#eaf3ff";
crmForm.all.fieldname.style.borderColor = "#c5c5c5";

Hope this helps. Cheers!

Setting a CRM 4.0 Lookup field in JavaScript

It seems that the days are getting busier as I’m finalizing a couple of projects and preparing for TechEd 2010. Still, I want to still try and drop at least a couple of trinkets off here so you’ll keep reading this blog.

So what is today’s pearl of wisdom? I get asked all the time how to set the value of a lookup field in CRM via JavaScript.

It’s not quite as straightforward as setting the value of a textbox or picklist, but it’s not terrible. Basically, it boils down to a few steps.

The first thing to remember is that the value of a lookup field is an array of objects. My understanding is that by default you can’t actually create a CRM lookup field that accepts multiple values. However, a good example of this is in the CRM email entity’s “To” or “CC” fields. These fields allow you to set multiple recipients for an email.

The second thing to remember is that despite the fact that you can’t set multiple values, you can set a single value but that value is a complex type, an object with individual properties, not just an intrinsic type like a string or integer.

So how do we accomplish that in JavaScript? First, we’ll create an object:

var lookupObject = new Object;

Now that we have our object, we can set some values. Typically, you’ll want to set 3 main properties: ID, name, and typename. The ID is the GUID of the object whose value you’re setting. The name is the string that your users will see. Finally, the typename is the CRM entity name for the value you’re setting, in this case systemuser. You can set them like this:

lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";

OK, so now you’ve set the values for the object that you’ll be setting as the value of your lookup. As I mentioned though the value of a lookup field is an array of objects, even if you can only set a single value. So we can create the array like so:

var lookupObjectArray = new Array();

We can only set one object, so we’ll set our new object as the first member of our newly created array.

lookupObjectArray[0] = lookupObject;

Alright, now that we have our array and its first member is our object, let’s set the array as the lookup field’s DataValue:

crmForm.all.new_userid.DataValue = lookupObjectArray;

Finally, we want to make sure that our newly submitted value gets saved back to the database when we save the record, and we can accomplish that quite simply by setting ForceSubmit to true:

crmForm.all.new_userid.ForceSubmit = true;

There we have it! We created an object, a container array, set the appropriate values and assigned it to out lookup field. Here’s all the code together in one block:

var lookupObject = new Object;
var lookupObjectArray = new Array();
lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] = lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;
crmForm.all.new_userid.ForceSubmit = true;

Cheers!

Easy Access to the crmForm.ObjectId from CRM 4.0 entities

Note: The content in this post, like most of my posts, is likely unsupported.

Warning: This is a lot of content for a very few lines of code. I ramble so that you can learn the how and the why. More advanced developers and/or less patient readers may want to go straight for the code.

If you’re anything like me, you spend a lot of time in CRM. I love it, as does most anyone I’ve met who’s tried it. Having said that, there are a few things about it that are intentionally hidden from the user’s view and with good reason.

A great example of that is the address bar. For most of us who deal with CRM, we know that CRM keeps track of entities by using GUIDs. Furthermore, we know that the easiest built-in way to get the current entity’s GUID is to get it from the URL. One quick way to do that is to hit F11 which will cause the current browser window to go full screen and the address bar is available by moving your mouse to the top of the window. It’s a little annoying because it usually takes me 3 steps:

  1. You have to hit F11 and move the mouse to the top of the window to show the address bar.
  2. You have to click in the address box, which usually makes the address bar hide itself, so you have to click in it again.
  3. You have to highlight only the GUID before copying it, or copy and paste the whole URL and remove everything but the GUID.

Now if you haven’t been exposed to that method, you’re welcome, but hang on because this post should save you the trouble. 3 repetitive steps that annoy me and are preventable are usually enough for me to search for a programmatic solution. I’m a developer and I live by DRY. (Don’t repeat yourself)

So there are many ways to accomplish this I’m sure, but here’s my way. I should mention here that I tend to deal with the database side of things a great deal as well, so I knew from the beginning that I wanted to copy the GUID to my clipboard.

Initially my thought was to add a button to the toolbar, or maybe even add a copy command to the actions menu, but while I was making this little snippet I realized that often times I’m running database queries against these GUIDs and it would be nice to see the GUID on the screen at all times. I decided to tap into the status bar. For all the entities I checked it’s always down there, and it seems to always have room enough for some other text, say… a GUID. 🙂

My approach: This is actually pretty straight-forward. Each entity’s form has a crmForm.ObjectId (yes, case sensitive) that is the GUID for the current record. So, I figured I would add some JavaScript to embed the ObjectId in a UI element on the form. Nowadays, anytime I hear JavaScript I think jQuery. So, how to get jQuery on a CRM form? This has been documented in several places on the interwebs. Before I post it here online, I need to ask the person I got it from if I can share this particular approach.

Now that you’re referencing jQuery, you have a little horsepower behind you. So, let’s add the line that will show the GUID in the status bar:

$("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span>");

Huh? What’s all that? Let’s break it down:

  • First, it finds the element whose id is crmRenderStatus.
  • Next, it finds the closest td tag (in this case, its parent td)
  • Then, it appends the HTML that I’m specifying while injecting the crmForm.ObjectId

Here’s the result:

image

What you wind up with is quite simply the GUID nested in a span tag, positioned right next to the Status on the status bar. It’s important to note that the fact that I’ve tucked the content in a span tag with a specific ID property is both intentional and required. Great! Now I can see the GUID, but I can’t copy it. How can I fix that? Easy enough. Just use good old jQuery again and wire up a double click event handler to the GetObjectId span that contains the GUID, like this:

$("#GetObjectId").dblclick(function() {
    window.clipboardData.setData('Text', this.innerHTML);
});

Does that look like Greek? OK, let’s break that down:

  • First, we’ll find our newly added span element with the id of GetObjectId.
  • Next, we’ll attach a handler to the double click event (jQuery .dblclick method).
  • Finally, we’re defining an anonymous function that details what we want to do when the double click event fires.

Now this works, but you don’t get any visual indication that you’ve copied the GUID. To handle this, I’m changing the “UI modification” line to include a span that just has the text ” Copied…”. This line starts out invisible since you haven’t copied the GUID until you double click on it.

$("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span><span id='ObjectIdCopied' style='display:none;'>&nbsp;Copied...</span>");

I’m also going to change the handler’s anonymous function to show the ” Copied…” text by fading it in and to allow them to get a second copy indication by fading it out.

$("#GetObjectId").dblclick(function() {
    window.clipboardData.setData('Text', this.innerHTML);
    $("#ObjectIdCopied").fadeIn("fast").fadeOut("slow");
});

This results in a brief moment that looks like this (insert imagined fade-in and fade-out here)
image

There we have it. A few lines of code that save me some hassle many times throughout the day. You can see the detail in this post by Jim Wang, but the other thing that I do is wrap this in an if statement that checks to make sure that all this only happens if you’re a System Administrator or System Customizer. Alright, I warned you this was a long post for such a small amount of code. Here’s the code all wrapped up. Hope this helps!

if (UserHasRole("System Administrator") || UserHasRole("System Customizer"))
{
     $("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span><span id='ObjectIdCopied' style='display:none;'>&nbsp;Copied...</span>");
     $("#GetObjectId").dblclick(function(){
         window.clipboardData.setData('Text', this.innerHTML);
         $("#ObjectIdCopied").fadeIn("fast").fadeOut("slow");
    });
}

There is one other addition to all of this which you may have noticed. We use a UserHasRole method to make sure that I’m not showing everyone the GUID. That’s not because I want to keep it a secret, it’s because I don’t need users telling me that CRM is emiting corrupted text.

Cheers!

Microsoft releases new CRM case study : Access MediQuip

Well, I have to say that I’m flattered. It’s always great to look back on what you’ve created and get a sense of self-fulfillment. For me, today is no exception. I work for Access MediQuip as their lead developer and software architect. We deal with challenges every day – don’t we all? – and I have to say that I really enjoy them, or more specifically overcoming them. It feels good to be proud of what you’ve made, it feels great when your boss tells you that you’ve done a great job, but it feels pretty stellar when Microsoft likes it enough to write a case study about it.

I have to say that although the proverbial buck stops here when it comes to our solution, it’s great to have had the opportunity to work with great people too. While a lot of the development for our platform has been handled in-house, I was able to draw on the expertise of leaders in the industry as well. I knew that I wanted to involve someone who , like me, could “bring the heat” and in my mind that meant a Microsoft MVP.

In particular, I’m referring to none other than Mitch Milam. Mitch is Chief Technologist at CRM Accelerators and is a Microsoft CRM MVP. He brought the skills I was looking for in the CRM space. I’ve worked with Mitch since March of last year, and it’s been great. I’m not just ‘blowing sunshine up his skirt’ either. It continues to be a great experience, and I can highly recommend him to any clients looking to push the CRM/xRM envelope. I think we’ve both grown from working with each other, and I plan on continuing that growth. Cheers Mitch! – now where’s my $5? 😉

I love looking back on what I’ve created, but I have to say that it’s the tip of the iceberg in comparison with what we want to do with xRM. I’ll keep you posted for what interesting tid-bits I can share.

Here’s a link to the case study:

http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?casestudyid=4000006368

Mitch’s blog can be found here:

http://blogs.infinite-x.net/

CRM 4.0 Update Rollup 8 released

Microsoft released CRM 4.0 Update Rollup 8 yesterday. This rollup is packed with fixes, most notably:

  • E-mail Router support for Exchange 2010 and for Exchange Web services is added.
  • Users cannot assign activities after the activities are deleted from a queue.
  • Although Microsoft Office 2010 is still in beta and is not officially supported, Microsoft Dynamics CRM 4.0 was tested together with Microsoft Office 2010.

2010 here we come! A great job by the CRM Dev Team for the continuous stream of updates. I really think it helps to keep CRM a vibrant and robust platform. Kudos! You can always check the Microsoft Dynamics CRM Team Blog here.

Deleting a user the right way in CRM 4.0

I always enjoy getting stumped, and sometimes things come out of left field and you find yourself scratching your head for a while. This happened to me recently at work when I had a Help Desk ticket escalate out of the Help Desk and up to me. Now, normally I try to let the Help Desk staff run with problems because I think it’s important for their own professional growth but this had me digging and missing the obvious. The help desk ticket was as wordy as long-winded as you’d expect.

“User can’t add items to order”.

Such incredible insight in 6 short words. OK, I’ll be honest, an order number would have helped but I wasn’t going to hold my breath. So, I try to add an item to an order and it works just fine. Later, I get a screenshot and an order number so I figure we’re in business. But what’s this?

Error
“The selected user or the user trying to log on has not been assigned a security role, and does not have sufficient privileges for this action. For more information, contact your Microsoft Dynamics CRM administrator.”

OK, that’s odd. This is clearly a built-in CRM error message. I quickly check the user’s roles and everything’s just fine, so I try to add an item to the order myself. My assumption is that since I’m a System Administrator I shouldn’t have a problem, but I do. Same error message! How can this be!? Well, if it’s happening to me as a System Administrator, then it must not be my roles in question and it isn’t the users. “The selected user”…. of course! This isn’t my order, so let me check the security roles belong to the order’s owning user. Take a look at the image and tell me what’s missing.

NoRoles

Guessed it yet? No Roles! In our case, the owner of the order was user that was no longer with the company. Someone on the Help Desk staff took it upon themselves to simply remove all the user’s roles in CRM an assumed that was sufficient.  In fact, the user’s account was still active.

So what is the appropriate route for dealing with user’s in such a case? My suggestion would involve 2 steps:

1. If the user isn’t with the company anymore, someone will likely take over their work load. The CRM Dev Team has thought about this and has added a handy little feature for doing just that.

ReassignRecords

Simply open the user form for the user in question, hit the Actions menu, and choose Reassign Records. Doing so allows you to reassign them to yourself or another user, as shown below.

ChooseReassignRecipient

Do take the time to read the text in the yellow box. It doesn’t matter what state the record is in, if you reassign it to yourself, it’s yours. That includes all deactivated records too.

2. Now that all the records belong to someone else, you should disable the user’s account so that it’s tucked away for safekeeping.

Cheers!