Dynamics CRM Form Script and Useful JavaScript Snippets

Getting Started with Dynamics CRM Form Script

There are LOTS of good resources for learning how to write Dynamics CRM form script — i.e., placing JavaScript code behind the onLoad and onSave form events, and behind the onChange event of any field on a form. Probably the best starting place is the Dynamics CRM SDK. If you need to learn how to customize Dynamics CRM, topics like the one in this article are covered in my one-day live online training class, Customizing Dynamics CRM and the xRM Platform

But rather than give you a link to it, here’s a link to the MSDN Developer Center for Dynamics CRM. This page is a fantastic resource and a good uber-starting point, since it’s got the SDK link front and center, plus a lot more.

Form script can do a lot of different things, but the common denominator of all CRM form scripts is that they a) respond to data a user enters on a form, and/or b) update the display of information on a form. They can certainly do complicated things; for example, web services can be called to query information from your CRM server or to interact with an external application. But it’s important to remember, and easy to forget (at least for me!) that they really are form-centric.  That is, they only happen if a user is interacting with the form they’re written for. To clarify what this means, compare workflows with form script:

  • An automatic workflow written for the Lead entity, with a scope of “Organization” and triggered on the Create event will always run when a new lead record is created, no matter how it’s created.
  • JavaScript in the onLoad event of the Lead form will always run when a new lead record is created…but only IF that new record happens to be created by a user using the Dynamics CRM lead form.  

There are lots of ways records can be created without having their form open, so you have to take account of situations like these in your applications design:

  • A contact can be created in Dynamics CRM when a user of the Outlook client clicks “Track in CRM” for one or more Outlook contacts.
  • Most record types in Dynamics CRM — including leads, contacts, accounts, opportunities, cases… — can be created with workflows.
  • External applications can use web services to update the Dynamics CRM database. For example, Web2CRM and other “Internet lead capture” add-ons let you create leads or other record types based on the information provided in and submitted from a web form.  

Alternatives to Form Scripting

If you’re coding for the on-premise version of Dynamics CRM 4.0, you can write what’s called a “plug-in” and tap into the so-called “event pipeline” for most record types. Essentially, this will be a compiled DLL, deployed on the server, and can make certain things happen whenever a record is created (or before it’s deleted and lots of other scenarios) regardless of how it’s created. The Dynamics CRM SDK has lots of examples of the kinds of things you can do with these, and complete samples including code.

If you’re working with Dynamics CRM Online, as yet plug-ins aren’t supported (nor are custom workflows written with Visual Studio and the Windows Workflow Foundation), so the best you can do is with “regular” Dynamics CRM workflows, of the type I cover in my book, Building Workflows in Dynamics CRM 4.0.  

So you can think of three different approaches of writing event-driven applications for Dynamics CRM: Form script, Dynamics CRM workflows, and plug-ins. Here are a few of the ways they compare with each other:

  • Form script is not compiled and does not require a professional development environment like Visual Studio. It’s implemented as a “schema customization” (stored in the Dynamics CRM database), so it can be exported and imported, and gets backed up with your SQL. It’s relatively straightforward, although you can call web services with it, so it can do some relatively complex stuff (witness the InsideView mashup I’ve written about a few times.)
  • Dynamics CRM workflows can run “on demand” or can be triggered automatically when a record is created, assigned, updated has its status changed, or deleted. Workflows run asynchronously and often take around 30 seconds to complete. This generally makes them a bad choice for the things form-scripting excels at, like updating form values based on a user’s input.
  • Plug-ins have the fewest limitations of these three approaches, but also the highest bar in terms of professional development skills and tools. One disadvantage of plug-ins compared to the other two approaches is that they are external DLLs, not stored as metadata in the Dynamics CRM database. This makes them less portable, means they require separate backup and restore procedures and so forth.    

 Here’s a table that compares the three approaches:

Characteristic Form Script Dynamics CRM Workflows Plug-ins
Requires VS and professional development experience? No No Yes
Schema customization (stored in Dynamics CRM database)? Yes Yes No
Immediate user-interface responsiveness? Yes No Yes
Always runs? No: requires form to be opened Yes, if configured to Yes
Rich event model? Somewhat Somewhat Yes

 A Few Useful Examples of Dynamics CRM Form Script

That being said, form script is incredibly useful, and should probably be in your repertoire if you’re a working Dynamics CRM professional. You don’t have to be pushing the Dynamics CRM envelope to come up with requirements for which it’s the best solution, and after you use it for a while you find yourself solving the same problems over and over again. Here are a few examples:

Calculated Fields

Suppose you’ve got numeric fields named new_field1, new_field2, and new_total and they’re all placed on a form. The following JavaScript in new_field1 and new_field2’s onChange event will effectively make new_total a calculated field:

crmForm.all.new_total.DataValue = crmForm.all.new_field1.DataValue + crmForm.all.new_field1.DataValue;

Since the new_total field is calculated, you don’t want users entering anything into it. So you can “disable” it, by placing code like the following into the form’s onLoad event:

crmForm.all.new_total.Disabled = true;

But if you do that, enter some data, save the record and re-open it, you’ll notice that the total value isn’t saved. Since that doesn’t happen by default, you can add the following code to the form’s onSave event to force it to happen:

crmForm.all.new_total.ForceSubmit = true;

Hiding and Showing Sections and Tabs

Dynamics CRM forms are composed of tabs (up to eight of them) and sections (hmmm…how many sections can you have on a tab?). I often encounter a requirement to show or hide tabs or sections on tabs depending on things a user might select, such as a value in a picklist for the current sales stage of an opportunity, to pick one common example. Hiding or showing tabs is straightforward. For example, suppose based on a selection in a picklist you want to hide a form’s third tab and show its second one. This form in the picklist’s onChange event will do that, keeping in mind that tabs and sections are both zero-based, so count from 0 to 4 instead of from 1 to 5:

//hide the third tab:
crmForm.all.tab2Tab.style.visibility = "hidden";
//show the second tab:
crmForm.all.tab1Tab.style.visibility = "visible";

What about hiding or showing a section based on user input, for a more granular result? The next snippet is more self-contained than the others I’ve shown, and illustrates a number of useful (and re-usable!) things. This is written for the onChange event of the Status Reason picklist, and it shows or hides sections on the second tab of a customized opportunity form, depending on which sales stage an opportunity record is at.

switch (crmForm.all.statuscode.SelectedText)
{
  case "1. Qualification":
      HideSection (1, 0, "");
      HideSection (1, 1, "none");
      HideSection (1, 2, "none");
      HideSection (1, 3, "none");
    break;
  case "2. Prepare Solution":
      HideSection (1, 0, "none");
      HideSection (1, 1, "");
      HideSection (1, 2, "none");
      HideSection (1, 3, "none");
      break; 
}
function HideSection( tabIndex , sectionIndex , displayType )
{
      var tab2Hide = document.getElementById( "tab" + tabIndex );
      tab2Hide.childNodes[0].rows[ sectionIndex ].style.display = displayType;
}

What else does this show besides the useful and very re-usable function HideSection?

  • Use of a customized Status Reason field for sales pipeline stages.
  • Syntax for a switch statement on the SelectedText property of a picklist field — a very common requirement. 

This can be adapted for all kinds of different scenarios.

Working with Dates and Setting Default Values

It took me a while to get used to working with dates in JavaScript. Remember: the reason you need to work with dates in JavaScript is if you have to work with values in date fields on a Dynamics CRM form. So here’s an example that shows how, for a custom entity that manages subscriptions, you might set default values for a subscription’s start date and its end date. The example here shows it for an annual (365-day) subscription, and obviously you could adapt this to your own situation. This code can go into the entity form’s onLoad event:

var CRM_FORM_TYPE_CREATE = 1;
var CRM_FORM_TYPE_UPDATE = 2;
switch (crmForm.FormType)
{
  case CRM_FORM_TYPE_CREATE:
      //define two variables, one as a date with today's date in it:
      var currentdate = new Date();
      var subscriptionend;
     
      //put the current date in the startdate form field:
      crmForm.all.new_startdate.DataValue = currentdate;
      //use setDate and getDate methods to add 365 days to currentdate,
      //put value into enddate form field:
      subscriptionend = currentdate.setDate( currentdate.getDate() + 365);
      crmForm.all.new_enddate.DataValue = subscriptionend;
     
      break;
  case CRM_FORM_TYPE_UPDATE:
      break;
}

Besides the JavaScript date manipulation, this code shows the standard approach for handling the different results you want when a form is loaded for a new record (default values should be set in this case) as opposed to when it’s opened to edit an existing record (the data are already entered so you don’t want to re-set their values in this case).

If you’ve got good snippets I can use as examples, feel free to send them along. One thing about form script like this is you do tend to use it over and over again. Rather than have to re-remember it all the time, I figure I might as well post it up on my blog and free up some of my memory for more important things. Such as Bridget’s List of Things to Know:

Bridgets-List

Bridget's List of Things to Know

 

Richard Knudson
May 23, 2010

14 Comments »

  1. mde3 Said,

    May 24, 2010 @ 9:54 am

    I liked the comparison table. It really helps to have something like this when I am working with developers new to crm. It helps them understand where and when they need to do custom code.

  2. Neil Benson Said,

    May 25, 2010 @ 2:06 am

    I like Bridget’s list of things to know, but one other useful thing to know which, if I were Bridget I would add to my list, is: the metric system ; )

  3. Richard Knudson Said,

    May 25, 2010 @ 6:56 am

    Hi Neil — thanks for the comment. You’ve got a point about the list. It does have a bit of an anglo-american focus to it. But she learns about the metric system and things like the Euro/dollar exchange rate at school, so measures like “feet” and “miles”, and dates like “1066″ are really in the category of extra credit.

  4. Andrew Wolfe Said,

    May 25, 2010 @ 9:25 am

    crmForm.all.tab2Tab.style.visibility = “hidden”;

    will hide the second tab but leave a gap if there’s a third tab. style.display = “none”; like you use for your section hiding is a better choice?

  5. Form-Scripting - TIDBITS on Microsoft Dynamics CRM Said,

    May 27, 2010 @ 6:12 am

    [...] his continued awesome way, Richard Knudson writes up and shares a nice post on Form-Scripting in Microsoft Dynamics CRM. What is he referring to with regards to Form [...]

  6. Frank van Delden Said,

    May 27, 2010 @ 8:06 am

    Can I use this post (in referal) on my blog and extend it with more examples?

    It is a great and usefull post!

  7. Richard Knudson Said,

    May 27, 2010 @ 9:07 am

    Hi Frank,

    Thanks for the note, and by all means use it/refer to it on your blog and extend with examples. I’ll do the same here if you share the examples with me. What’s your blog, btw?

    Richard

  8. Louay Said,

    June 9, 2010 @ 6:31 am

    Hi Richard,
    Thank you for the useful post above, I am sure it benifited everyone in here.
    I have a quick question if possible, I need to customize the pop-up form used when you click “Convert Lead” in the Lead Entity. I need to modify a bit the drop down menu for disqualified lead and maybe add my own attributes there.
    Can you please guide me how to accomplish this?
    Thanking you.

  9. Jason Taormina Said,

    June 11, 2010 @ 9:39 am

    Hi,

    In our company, we have a lot of reoccurring revenue, so I added Length of Contract and Revenue/Term attributes to the opportunity entity. In addition, most projects have an upfront amount as well. I used created scripts in the onChange event for these fields to compute the Total Revenue, as follows:

    total revenue = one time + (length x monthly rate)

    This isn’t working, though. When I fill in the fields, nothing happens. When I save, nothing happens. Is there some incompatability between the integer type and the money type?

    -Jason

  10. Richard Knudson Said,

    June 13, 2010 @ 6:16 am

    Hi Jason — thanks for the note.

    Money and Integer attributes work together OK, so I don’t think that’s the problem. I just did an example that I think is the same as yours at least conceptually. Here’s a self-documenting JavaScript snippet that I put in the onChange of Estimated Revenue (schema name estimatedvalue) and called from the onChange events of the custom fields with the crmForm.all.estimatedvalue.FireOnChange(); trick, but it works just as well if you put this code in the onChange event of each contributing field:

    //estimatedvalue is the built-in attribute with display name ‘Estimated Revenue’
    //new_upfront is a custom attribute of type money
    //new_duration is a custom attribute of type integer
    //new_rate is a custom attribute of type money

    crmForm.all.estimatedvalue.DataValue =
    crmForm.all.new_upfront.DataValue +
    (crmForm.all.new_duration.DataValue * crmForm.all.new_rate.DataValue);

    I bet it’s a syntax problem or something along those lines. Give it a shot and let me know how it works out!

  11. Useful Form Scripts #4 Said,

    June 15, 2010 @ 7:04 am

    [...] field only gets updated when the form is loaded. I pointed this out in a general way in the Form Script #1 article, but the current example really drives the point home: there’s no true calculated field type [...]

  12. Richard Knudson Said,

    June 17, 2010 @ 9:30 am

    Louay, I missed your question about lead conversions for a few days — sorry about the slow response. Here’s the thing about customizing the lead conversion dialog: it’s not supported in the current version of the product. What does “supported” mean? Another good question. Mainly:

    - not supported in case you need technical support from MS
    - not supported for upgrades
    - possibly can break your CRM

    That being said…”not supported” doesn’t mean it can’t be done. Here’s a link to an article by Nishant Rana that shows how to do some customization to the dialog using the document object model (DOM) in JavaScript. http://nishantrana.wordpress.com/2010/04/22/customizing-convert-lead-dialog-box-in-crm-4/

    Cheers – Richard

  13. Top 20 Dynamics CRM Industry Solutions Said,

    August 22, 2010 @ 3:43 pm

    [...] list of the Beatles Top 100 songs, baseball statistics like the Top 100 Hitting Charts, Bridget’s list of things to know, biggest cities, top 10 towns named after elements, lists of lists (those would be meta-lists, I [...]

  14. Top 20 Dynamics CRM Industry Solutions - Richard Knudson’s Microsoft Dynamics CRM Trick Bag Said,

    August 22, 2010 @ 4:34 pm

    [...] list of the Beatles Top 100 songs, baseball statistics like the Top 100 Hitting Charts, Bridget’s list of things to know, biggest cities, top 10 towns named after elements, lists of lists (those would be meta-lists, I [...]

Leave a Comment