Using jQuery with MS CRM 4.0

Published 11/21/2008 by Henry in CRM | Javascript | jQuery

Doing a MS CRM 4.0 project, where the requirement is to create a toolbar button on a detailform.
This button needs to open a window (prefferably a modal window). In this window users can make some selections and when submitting, some processing will be done using these selections, this is not important for this post.

When thinking about this requirement, I really wanted to use something like the ASP.NET AJAX Control ToolKit's Modal Popup. Also I am really impressed by jQuery, a JavaScript library, that is an elegant and easy to use abstraction over JavaScript. It simplifies document traversing, event handling, animation and Ajax interactions. I knew about jqModal a jQuery plugin that simplifies display of dialogs and modal windows.

NOT FULLY SUPPORTED
If you are a developer
working with MS CRM, you know that it is higly customizable, but within it's own boundries. An important matter on this project particularly is that customizations need to be supported by Microsoft. What I am about to explain is NOT FULLY SUPPORTED, because I will use external.js files, using a link element to import it in the page. But I want to explain also, that it is possible to do this without using external files, you could paste the contents of the 'jquery-1.2.6.min.js' file into the onload function of the detailform's property window.

I wanted to give it a try, because, well just think about the possibilities for a while. If you can use jQuery in CRM development, a lot of possibilities open up.

FIRST STEPS
So the first thing to do is to put the 'jquery-1.2.6.min.js' file in a '_customscript' folder in the CRMWEB root folder. Next I need a way to reference the file, so it's contents can be called from the page. Like I already posted in my blogpost External js file and CRM, I like to do this using the Msxml2.XMLHTTP object. The function reads the contents of a file and imports all functions found into the current namespace, so they are accessible.

   1:  function load_script (url) 
   2:  { 
   3:      var x = new ActiveXObject("Msxml2.XMLHTTP"); 
   4:      x.open('GET', url, false); x.send(''); 
   5:      eval(x.responseText); 
   6:      var s = x.responseText.split(/\n/); 
   7:      var r = /^function\s*([a-z_]+)/i; 
   8:      for (var i = 0; i < s.length; i++) 
   9:      { 
  10:          var m = r.exec(s[i]); 
  11:          if (m != null) 
  12:              window[m[1]] = eval(m[1]); 
  13:      } 
  14:  } 
  15:   
  16:  load_script("/_customscript/jquery-1.2.6.min.js"); 
  17:  load_script("/_customscript/jqModal.js"); 
  18:  load_script("/_customscript/jqDnR.js"); 
  19:  load_script("/_customscript/customscript.js"); 

Listing 1

As you can read in listing 1, the 'jqModal.js' file is also referenced, this holds the jqModal library, I also load 'jqDnR.js' a jQuery library that supports dragging and resizing. I also load 'customscript.js', this is a custom javascript file that will hold the function that is called when the button on the details window is clicked.

CSS STYLESHEET
Because we do not want to mess with the stylesheets used by CRM we also need to add a stylesheet containig the modal window's styles to the filesystem. I made a css folder below the _customscript folder, the folder where I put the javascript libraries. You could add these styles through Dom manipulation in JavaScript also, to keep the customization supported by Microsoft!
I use the following code, you can do this in the OnLoad function of the details form, or in a separate function, that you call from the Onload function. I use the function that also checks if the reference exists already, but for simplicity put this in the On Load after listing 1.

   1:  var styleSheet = '/_customscript/css/modalWindow.css';
   2:  var head = document.getElementsByTagName("head")[0];
   3:  var linkElement = document.createElement('<link rel="stylesheet" type="text/css" href="'+ styleSheet +'" />');
   4:  head.appendChild(linkElement);

Listing 2

In listing 2 I create a link element with a reference to a style sheet and append this element to the head element of the html page (CRM's detail form).

Listing 3 will display the contents of the css style sheet:

   1:  .jqmWindow  
   2:  { 
   3:  	display: none; 
   4:  	position: fixed; 
   5:  	top: 17%; 
   6:  	left: 50%; 
   7:  	margin-left: -300px; 
   8:  	background-color: #E4EEF9; 
   9:  	border-width: 1px; 
  10:  	border-style: solid; 
  11:  	border-color: #0a6cce; 
  12:  	padding: 0px; 
  13:  	width: 374px; 
  12:  	height: 264px; 
  13:  } 
  14:  
  15:  .jqmOverlay { filter: alpha(opacity=70); opacity: 0.7; }
  16:  
  17:  .jqmTitle 
  18:  { 
  19:  	cursor: move; 
  20:  	background-color: #6793CC; 
  21:  	border: solid 1px #6793CC; 
  22:  	color: #FFFFFF; 
  23:  	font-weight: bold; 
  24:  	width: 100%; 
  25:  } 
  26:  
  27:  .jqmTitleText { float: left; position: relative; }
  28:  
  29:   /* Fixed posistioning emulation for IE6  
  30:      Star selector used to hide definition from browsers other than IE6  
  31:      For valid CSS, use a conditional include instead */  
  32:  * html .jqmWindow 
  33:  { 
  34:    position: absolute; 
  35:    top: expression((document.documentElement.scrollTop || document.body.scrollTop) + 
  36:         Math.round(17 * (document.documentElement.offsetHeight || document.body.clientHeight) / 100) + 'px'); 
  37:  } 
  38:  
  39:  .jqmIFrame { width: 100%; height: 100%; }
  40:  
  41:  .jqmClose 
  42:  {  
  43:    width: 20px; 
  44:  	font-weight: bold; 
  45:    float: right; 
  46:  	cursor: pointer; 
  47:    color: #FFFFFF; 
  48:  	background: #6793CC; 
  49:    border: 1px solid #6793CC; 
  50:  }  

Listing 3

CREATE DIV (MODAL WINDOW)
Next we need to add the div to CRM's details page. I wanted to this using the DOM, but for some reason it would not work. If anybody knows the reason why, please let me know!
Instead i used  the following approach, again: you can do this in the OnLoad function of the details form, or in a separate function, that you call from the Onload function.
In the real world project I use the function, but for simplicity in this example, I just put this in the On Load after listing 2.

   1:  // Not using dom to add new elements, because for some reason that does not work!
   2:  var body = document.getElementsByTagName("body")[0];
   3:  var modalDiv = document.createElement('<div id="dialog" class="jqmWindow" ></div>');
   4:  var titleDiv = document.createElement('<div id="jqmTitle" class="jqmTitle"></div>');
   5:  var modalTitle = document.createElement('<span id="jqmTitleText" class="jqmTitleText"></span>');
   6:  modalTitle.innerText = 'Documentenuitvoer';
   7:      
   8:  var modalButton = document.createElement('<button class="jqmClose" ></button>');
   9:  modalButton.innerText = 'X';
  10:      
  11:  var modalIFrame = document.createElement('<iframe id="jqmContent" class="jqmIFrame" frameborder="0" scrolling="no"></iframe>');
  12:  titleDiv.appendChild(modalButton);
  13:  titleDiv.appendChild(modalTitle);
  14:      
  15:  modalDiv.appendChild(titleDiv);
  16:  modalDiv.appendChild(modalIFrame);  
  17:      
  18:  body.appendChild(modalDiv);

Listing 4

As you can read in listing 4 first I get the body element and assign it to the 'body' variable. Than I create two div elements, the reason I do not create a div element and use setAttribute to set the attributes, but create the element in one line using a string containing the whole tag is that I could not get it to work, again let me know if you do! The first div will be our modal window. The second with id 'jqmTitle' is the header. Next I Create a span that will contain the text for the header, a (close) button that will be placed in the header on the right side.
And an iframe, in this iframe any (custom) page can be loaded.

INITIALIZE MODAL WINDOW USING jQUERY
To initialize the modal window, we have to add listing 5 to the OnLoad function of the details form in CRM after listing 4.

   1:  $().ready(function() {
   2:    $('#dialog').jqm();
   3:    $('#dialog').jqm().jqDrag('#jqmTitle'); 
   4:  });

Listing 5

In Listing 5 we use jQuery syntax. We attach the code to the OnReadyState eventhandler of the document. when the document is fully loaded the element with id 'dialog' will be registered as a jqModal window by line 2. Line 3 registers the dragging functionality of the element with id 'jqmTitle' inside the modal window (our header div).

CUSTOMIZE ISV.CONFIG XML
Now we only have to do two more things, the first is that we have to change isv.config.xml to create the button on our detail form, I use the contact and need the modal window functionality on the contact entity's form. I made the following change to the isv.config.xml:

   1:  <!-- Microsoft Customer Relationship Management Entities (Objects) -->
   2:  <Entities>
   3:      <Entity name="contact">
   4:        <MenuBar>
   5:          <CustomMenus>
   6:            <Menu>
   7:              <Titles>
   8:                <Title LCID="1043" Text="Documenten" />
   9:              </Titles>
  10:              <MenuItem JavaScript="ShowModalWindow();">
  11:                <Titles>
  12:                  <Title LCID="1043" Text="Plaats document in DocumentUitvoer" />
  13:                </Titles>
  14:              </MenuItem>
  15:            </Menu>
  16:          </CustomMenus>
  17:        </MenuBar>
  18:      </Entity>
  19:  </Entities>

Listing 6

Listing 6 displays part of the xml, the IsvConfig element holds an element configuration , which holds the Entities element. I need the contact Entity. The MenuBar element holds CustomMenus, which holds Menu. I added a Menu element with Title "Documenten" (LCID="1043" which means dutch). The Menu element holds MenuItem elements. I added a MenuItem element With a dutch Title and a JavaScript attribute that has the value 'ShowModalWindow()'. When we import the isv.config.xml and publish the customization changes, we see the menuitem is added.

CREATE JAVASCRIPT FUNCTION THAT SHOWS MODAL WINDOW 
In listing 1 on line 19 we saw that the external javascript file 'customscript.js' is loaded in the OnLoad function of the details form. 'customscript.js' is a custom  javascript file that holds the 'ShowModalWindow()' function.
As I mentiod earlier we had to do 2 more things, the first was the customization of the isv.config.xml and the second is to create this function: 

   1:  var customPagesVirtualDir = 'Custompages';
   2:   
   3:  function ShowModalWindow()
   4:  {
   5:      var contactId = crmForm.ObjectId;
   6:      var popUpUrl = '/' + customPagesVirtualDir + '/Popup.aspx?contactid=' + contactId;
   7:      $('#jqmContent').html('').attr('src', popUpUrl);
   8:      $('#dialog').jqmShow({modal: true});
   9:  }

Listing 7

Addition:  

I added line 1 after Imane pointed out the variable customPagesVirtualDir was not declared, thanks for telling me!

Listing 7 displays the 'ShowModalWindow()' function, the crmForm.ObjectId is assigned to a variable contactId. A variable popupUrl is filled with the url to a custom aspx page. Line 7 is jQuery syntax and assigns the url to the src attribute of the iframe inside the modal window. Line 8 opens the modal window and assigns true to the modal property, So the behaviour of the dialog will be like a modal dialog.

EXAMPLE

CRM's detail form contact entity
Picture 1: Contact details form

In the menu a button is added:


Picture 2: Menu item

 When a user clicks on the menu-item, the function ShowModalDialog is called in the external js file that is referenced in the OnLoad function of the page where the jQuery plugin loads the modal window (client-side!) and the users sees picture 3:

jQuery and jqModal in action on a contact details form
Picture 3: jQuery and jqModal in action on a contact details form

CONCLUSION
Personally I think this is awsome, jQuery is real easy to use and complex matters seem simple. It is a joy to use jQuery with CRM. This combination opens up a world of possibilities. Ofcourse CRM is a web application and customizable, so you could expect external libraries targeted to web applications to work with it. But for me the experience to open a modal dialog like this on a CRM details window without hacking CRM code...
Well I will stop rambling, you can judge yourself.

Henry Cordes
My thoughts exactly...


Comments (25) -

Pete | Reply

3/27/2009 12:59:00 PM #

Thanks for the code - it works but I can't seem to get the code to refresh with updates I've made.  I have made changes to the js files and saved them but if I step through the code it is loading the original code that was in the js files when I first ran the form.

Any ideas?

3/27/2009 8:18:26 PM #

Hi Pete,
Try emptying the cache, sometimes you even need to do an iisreset.
There are a few things you can do about the caching of your js files.
Look here:
ronaldlemmen.blogspot.com/.../...-and-caching.html
and
thecrmgrid.wordpress.com/.../

regards,

Henry

Kurt Gooding | Reply

4/20/2009 6:58:40 PM #

Great Article! Thanks.

4/21/2009 6:13:03 AM #

Glad you like it.

imane | Reply

8/29/2009 5:16:22 AM #

Hello and Thanks for the code,
but I have two problems
first:
I get an error when I add the listing5
second:
the program can not find "customPagesVirtualDir" which is in the listing7.

Any ideas please?

8/29/2009 1:43:24 PM #

Hi,
First:
What is the error and where did you place the xml exactly?

Second:
Thanks for pointing this out!
In my project, I use the 'customPagesVirtualDir' as a global variable althrough the code, I have placed it at the top of the .js file.
It is not declared in this tutorial, I will change it.

imane | Reply

8/30/2009 1:15:08 AM #

hi!
first:
I copy listing5 in the onload contact just after the listing4. and after publication when I open my window and I try to close it I have a Microsoft operating system message asking me if "I want to send this error or not"

Second:
I not use "customscript.js" so I copied the listing7 directly in the onload contact. and I called in this way "ShowModalWindow ();".

thank you in advance for your help

8/31/2009 1:38:12 AM #

Did you activate DevErrors in web.config, of CRM?
Hopefully you get more insight in the error that way.

Can you see details of the error in te MS system message?

It does not look like you have done something wrong, so you have to find out what exactly is going wrong

imane | Reply

8/31/2009 7:01:17 AM #

is not a " missing just before the last parenthesis of the function in listing5 ?
I tried to add but it's still not working

8/31/2009 11:26:17 AM #

The best thing to do, is add new code (listings) one at the time.
After each addition publish and try, if CRM still functions.
This is especially true for listing 6, the isv.config addition.
When you add the xml and run CRM after publishing, does the new menu-item appear?

You will have to 'debug', if it's the XML , you can try to show me the xml, maybe I can help there....

8/31/2009 11:38:32 AM #

I am sorry, but I think there is a html hick up in the markup of listing 5!

This is how it should be:

$().ready(function() {
   $('#dialog').jqm();
   $('#dialog').jqm().jqDrag('#jqmTitle');
});


I am sorry! I have fixed it.

imane | Reply

9/1/2009 1:30:36 AM #

yes Smile listing5 works but I have another problem:
when I click on "document Plaats in DocumentUitvoer" he told me he can not find the function ShowModal () (I copied in the onLoad contact).
after I copy the body of ShowModal () directly in the Isv.config.xml to see if it works but it gives me a small button (with a cross X above)in the bottom left of my registration.

Any ideas please?

9/2/2009 10:55:44 PM #

Maybe, this is not the problem, but the Javascript function is namrd: ShowModalWindow(); not ShowModal();

imane | Reply

9/4/2009 1:34:46 AM #

the problem is that the window is hidden behind the main window and it is impossible to Unhide.
is not a function to resize the window?.
thank you

9/4/2009 8:24:57 AM #

I do not understand how the behavior you are describing can take place.
The jQuery ModalDialog, is nothing more than a div that is made visible. The window has a width and height specified in the css from Listing 3:
width: 374px;
height: 264px;

Marcelo Cruz | Reply

4/4/2010 12:35:05 PM #

Great! It's working as well!
You have no idea of how much you helped us!
Thank you again...

4/4/2010 12:55:39 PM #

@ Marcelo Cruz,
No problem, glad to help!

Mohamed Hanafi | Reply

4/30/2010 5:15:33 AM #

I tried using the jquery calendar, but each time i select a date. alert is displayed as the CRM thinks i'm trying to navigate away from the page. because i hit links on the calendar. does anyone know how to disable the alert for the calendar selection only? i use the calendar because it supports Hijri date.

Thank you,

4/30/2010 10:13:07 AM #

@Mohamed Hanafi:
This is strange, are you using the datepicker from jquery.ui?
The links on this datepicker have an a tag with a href attribute that only has a '#' as it's value:

<a href="#"

and the parent td tag has:

<td onclick="DP_jQuery.datepicker._selectDay('#DateToSend',11,2010, this);return false;"

Where the 'return false;' part should prevent the href onclick to be executed.
Maybe if you can give some more info, I can help.

You can try using the IE developer toolbar (www.microsoft.com/.../details.aspx if you use IE 7, in case of IE 8 just use F12) to check what html and javascript the datepicker actually renders.

Tod | Reply

10/6/2010 4:46:55 PM #

Great article thanks,

I wanted to get jQuery and jQuery UI working on every form I have, ready and loaded.

What I did was add the following to _static\_common\scripts\global.js

[code]
var load_script = function(url)
{
   var x = new ActiveXObject("Msxml2.XMLHTTP");
   x.open('GET', url, false); x.send('');
   eval(x.responseText);
   var s = x.responseText.split(/\n/);
   var r = /^function\s*([a-z_]+)/i;
   for (var i = 0; i < s.length; i++)
   {
   var m = r.exec(s[i]);
   if (m != null)
   window[m[1]] = eval(m[1]);
   }
}

function window.onload()
{
    load_script("/_customscript/jquery-1.4.2.min.js");
    load_script("/_customscript/jquery-ui-1.8.4.custom.min.js");

    var styleSheet = '/_customscript/css/jquery-ui-1.8.4.custom.css';
    var head = document.getElementsByTagName("head")[0];
    var linkElement = document.createElement('<link rel="stylesheet" type="text/css" href="'+ styleSheet +'" />');
    head.appendChild(linkElement);
}
[/code]

This has certainly added jQuery to the form, I have yet to test jQuery UI. I assume it'll be fine, not so sure about the css, but it shouldn't be too hard to fix.

You will need to clear the cache of IE for this to take effect, global.js is cached. The developer tools can help there.

10/6/2010 11:32:16 PM #

@Tod:
Nice!

Tod | Reply

10/8/2010 1:37:15 PM #

Forgot this function too:

[code]
function IeRemoveFilterHack() {
                if ($.browser.msie) {
                    this.style.removeAttribute("filter");
                }
            }
[/code]

This gets rid of the special effect IE likes to add to text when jQuery fades it in.
e.g.
$('#SomeElement').fadeIn(1000, IeRemoveFilterHack);

Tod | Reply

10/13/2010 10:02:33 AM #

Going back over my code I noticed that this would stop the CRM web interface from navigating correctly though the Outlook interface wouldn't be affected.

So what I've done is move the code to a different javascript file:

\_static\_forms\FormAction.js

This is only loaded for forms and allows jQuery to be loaded without affecting navigation.

10/14/2010 6:59:03 AM #

@Tod:
Are you aware that adding the code into the \_static\_forms\FormAction.js file is not MS supported?

Tod | Reply

10/14/2010 7:47:07 AM #

No, I wasn't. Good to know, maybe someone can help with a location that is supported. Simply put; the global.js file can't have a window.onload and still maintain navigation in the web version. I guess the workaround would be to rename the window.onload function and call that on each form load.

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading