VisualForce Element Ids in jQuery selectors

I have retired this approach in favour of a much neater solution that can be found here.

This tricky topic had me puzzled for some time and in earlier posts I went the way of using CSS classes to identify DOM elements; but was always a touch dissatisfied with the solution. Not only is it less efficient – valid XHTML pages should only have one element with any Id, although CSS classes can be shared by many elements – but it also feels all hacky ‘n stuff. I’m a bit older now, a bit more experienced and I RTFM. Without further ado, here is why it’s tricky, and how to fix it.

As we know the elements within VisualForce pages are given unique Ids when they are rendered as HTML. Salesforce is super smart and generates these in a way such that each element Id is unique i.e. if your VisualForce code is structured so,

[code language=”xml”]
<apex:page id="page">
<apex:outputPanel id="panel">
</apex:outputPanel>
</apex:page>
[/code]

The rendered HTML for the outputPanel would be

[code language=”xml”]
<span id="page:panel">
</span>
[/code]

If you don’t specify Ids in your VisualForce code Salesforce generates the element Ids automatically, but will use the same Id pattern of ‘…:greatGrandParentId:grandParentId:parentId:elementId’. This creates a problem when try use Ids as jQuery selectors, and the reason is that jQuery uses CSS syntax when selecting elements. But the colon character is used to indicate pseudo classes within CSS code! How do we fix this? By escaping the character of course… all we need is a simple method that uses regular expressions to find the troublesome colon (there’s a punny joke in there somewhere) and escape the little guy(s),

[code language=”javascript”]
function esc(myid) {
return ‘#’ + myid.replace(/(:|\.)/g,’\\\\$1′);
}
[/code]

Note 1: We’re escaping both ‘.’ and ‘:’ for completeness.
Note 2: We have to escape the escape as the VisualForce parser seems to unescape the first escape :$

There, that should do it. A full example might be,

[code language=”xml”]
<apex:page id="page">
<script>
$(document).ready(function(){
$(esc(pnl)).css(‘background-color’,’blue’);
});
function esc(myid) {
return ‘#’ + myid.replace(/(:|\.)/g,’\\\\$1′);
}
</script>
<script> <!– I’ve list this code seperately as it’s part of another work-around* (but is still necessary if we’re using Ids) –>
var pnl = ‘{!$Component.panel}’;
</script>
<apex:outputPanel id="panel">
</apex:outputPanel>
</apex:page>
[/code]

*Post detailing the work-around
Now we have the freedom to select elements using either CSS classes or element Ids, and don’t have to worry about inefficient selectors or hacky code, errr… sortof.

34 thoughts on “VisualForce Element Ids in jQuery selectors”

  1. Some alternates that i use 🙂

    if you just want to match the id you selected entered in the component id parameter:

    – for your example you could do this:

    – jQuery(“#page\\:panel”) need to double escape it.

    – jQuery(“#:contains(‘XYZ’)”) -> will match all ids that contain xyz ie the above 🙂

    As always a great post wesman

    Reply
  2. Some alternates that i use 🙂

    if you just want to match the id you selected entered in the component id parameter:

    – for your example you could do this:

    – jQuery(“#page\\:panel”) need to double escape it.

    – jQuery(“#:contains(‘XYZ’)”) -> will match all ids that contain xyz ie the above 🙂

    As always a great post wesman

    Reply
  3. Great post! The one piece that scares me a little bit is Note 2:

    “We have to escape the escape as the VisualForce parser seems to unescape the first escape :$”

    Whatever is happening here, it is not normal, and if this behavior ever changes the script would stop working.

    Reply
  4. Great post! The one piece that scares me a little bit is Note 2:

    “We have to escape the escape as the VisualForce parser seems to unescape the first escape :$”

    Whatever is happening here, it is not normal, and if this behavior ever changes the script would stop working.

    Reply
  5. Jason,

    The visualforce parser sucks at parsing javascript that is embedded into the page. For example, write a for loop that iterates through an array of child nodes. Every time I have done that it hoses the javascript. As a general rule of thumb I move all of my JS into js file resource. The parser never touches it then.

    Reply
  6. Jason,

    The visualforce parser sucks at parsing javascript that is embedded into the page. For example, write a for loop that iterates through an array of child nodes. Every time I have done that it hoses the javascript. As a general rule of thumb I move all of my JS into js file resource. The parser never touches it then.

    Reply
    • Ah geez, thanks for the heads up. Just checking it out now and it seems my host has disable secure mail for some reason 😐 I’ll sort that out (or find a new host, which will probably be quicker).

      Reply
  7. Another alternative – relys on visualforce prepending its structured heirarchy naming – and ending with the id (making sure that it includes the leading semicolon). If you want to match items in a repeat/table you could use $(‘[id*=”:panel:”]’)

    $(document).ready(function(){
    $(‘[id$=”:panel”]’).css(‘background-color’,’blue’);
    });

    Reply
  8. Thanks for the post, FYI – I had to change the esc function to only single escape when I uploaded my function as a static resource and used in the html head.

    function esc(myid) {
    return ‘#’ + myid.replace(/(:|\.)/g,’\\\$1′);
    }

    Reply
  9. Thanks for the post, FYI – I had to change the esc function to only single escape when I uploaded my function as a static resource and used in the html head.

    function esc(myid) {
    return ‘#’ + myid.replace(/(:|\.)/g,’\\\$1′);
    }

    Reply

Leave a Comment