Friday, September 17, 2010

‘Gotchas’: Using jQueryUI to make popups in Visualforce pages

Awhile back, I decided to use JQuery and JQueryUI to help add some spice to our custom Visualforce pages. One of the features we use quite regularly is JQueryUI’s ‘Dialog’ widget to display interactive modal dialog boxes. You can view some great examples that cover the basics here along with the source code that will get you up and using the dialog widget quickly.

When we tried to use them in Visualforce the popups basically worked immediately, except that we found several critical ‘gotchas’ that took awhile to figure out. This article focuses on those issues and how we solved them.

Gotcha #1: jQuery conflicts with Salesforce’s built in javascript libraries

Salesforce uses a competing javascript library known as Prototype which is loaded up on all Visualforce pages. Both Prototype and jQuery use the ‘$’ character as a shortcut to their libraries. To avoid this, we redefine jQuery to use ‘j$’ instead. Make sure to always paste the following code into the beginning of any page you will be using jQuery on:

var j$ = jQuery.noConflict();

Note that this means you will always use ‘j$’ to reference the jQuery libraries, rather than just ‘$’.

Gotcha #2: The ‘:’ character is special in jQuery

When rendered in html, the ID given to a Visualforce element nearly always uses the ‘:’ character, which is beyond our control. However in jQuery, the ‘:’ is a special character and needs to be escaped. For example, the following lookup that tries to find a page element named ‘ThePageID:TheFormID’ will not work:


j$("#ThePageID:TheFormID");

To fix this, escape any colons with two backslashes:


j$("#ThePageID\\:TheFormID");


Gotcha #3: .dialog() will move your element outside of the form

This was perhaps the most annoying ‘feature’ of the jQueryUI dialog widget. Whenever you invoke the .dialog() method on a page element, the element gets moved to the bottom of the <body> section, and outside of the form it was in! For example if your HTML looked like this:

<html>
<body>
<form id="ThePageID:TheFormID">
<div id="MyPopup">Hi!</div>
</form>
</body>
</html>

And then you ran the following javascript to make ‘MyPopup’ a modal popup:

j$("#MyPopup").dialog({modal: true, autoOpen: false });

Your source HTML would now look something like this:

<html>
<body>
<form id="ThePageID:TheFormID">

</form>
<div id="MyPopup">Hi!</div>
</body>
</html>
The popup will still display just fine, but if your popup has any form elements on it (buttons, fields, etc.), they will need to be inside their original form, or else the data in them won’t get posted back to the server. This causes hair pulling when buttons aren’t working and values aren’t getting populated on the server side.

To fix this, make sure your <apex:form> tag has an ID specified. Then use jQuery to find it and put the popup back inside the <form> section. So, assuming my <form> tag has an id that renders as ‘ThePageID:TheFormID’ the code would look like this:

j$("#MyPopup").dialog({modal: true, autoOpen: false }).parent().appendTo(j$("#ThePageID\\:TheFormID"));

Note that this also must be done any time you invoke .dialog(), including when you open or close the dialog using .dialog(‘open’) or .dialog(‘close’).

Gotcha #4: Salesforce datepicker displays behind popups

I beat my head against a wall for too long on this one before figuring out what was going on. You know the little calendar that pops up with any date entry field?

image

If you put one of these in a jQuery popup, the calendar doesn’t display. The text box is there, and works fine, but the calendar popup is never displayed. As it turns out, it is because the calendar pops up behind the jQuery popup. To fix this, there is a zIndex property you can set when initializing the dialog. After some investigation and a bit of trial and error, I found the magic zIndex number to be 9. So make sure that when you initialize your dialog, you include ‘zIndex: 9’, like so:

j$("#MyPopup").dialog({modal: true, zIndex: 9 });

Gotcha #5: Handling validations on popups (Coming soon)

There is one last gotcha that deals with handling validations on jQuery popups. It is a bit tricky, so I decided it needs it’s own separate post. Check back soon!

7 comments:

  1. Thanks for this - it's been a great help for me.

    ReplyDelete
  2. 9? Why 9? Why not 999?

    Love your solution to #3 btw.

    ReplyDelete
  3. Great post Jason, Your solution #3 for jquery overlay(dialogs) is great, this problem was in discussion for so long.

    ReplyDelete
  4. Gotcha #3: .dialog() will move your element outside of the form


    Can you please provide with sample code in VF. Since i am unable to implement the same

    ReplyDelete
  5. Hi Jason,

    Thanks for the post - really helped getting started with JQuery and Visualforce.

    Did you ever get anywhere with dealing with point 5, handling validation in popups? I'm having that problem at the moment, and dont really want to go down the javascript and actionFunction route if I can avoid it.

    Cheers,
    Andrew

    ReplyDelete
  6. There is a problem with the month picklist and with the year picklist when inserting SF datePicker into JqueryUI Dialog (with modal = true). Theses picklists don't work.
    The fix is to add the ui-dialog class to the datePicker: into the JQ ready function, add:
    j$('#datePicker').addClass('ui-dialog');

    ReplyDelete
  7. hi jason,

    can we directly open vf page on custom button as popup?

    ReplyDelete