Using jquery selectors with dynamic visualforce

JQuery is a great js library, you can easily grab a component or list of components using any number of selectors.

Using it with visualforce can present a problem, however. When you specify an id attribute on a VF component, it outputs in a hierarchical colon separated value, for example:

<apex:page id="thePage">
  <apex:form id="theForm">
    <apex:outputPanel id="thePanel" />
  </apex:form>
</apex:page>

It will generate something of the following format for the innermost component:

<span id="thePage:theForm:thePanel" />

In order to reference this selector in JQuery, ideally you’d do the following:

$("#thePage:theForm:thePanel")

Unfortunately “:” is a special character in JQuery selectors, and will result in the following error:

Uncaught Syntax error, unrecognized expression: Syntax error, unrecognized expression: theForm

There are a number of ways to get around this.

  1. The simplest way is to provide a unique styleClass on the element, e.g.

        <apex:outputPanel id="thePanel" styleClass="thePanel" />
    

    which will generate

        <span id="thePage:theForm:thePanel" class="thePanel" />
    

    and at this point you can access it like this:

    $(".thePanel")
    

    Not a perfect solution, because classes really shouldn’t be forced to be unique, but it works.

  2. If you’re not accessing the id dynamically, you can double-blackslash escape the “:”, e.g.
    $("#thePage\\:theForm\\:thePanel")
    

    Kind of a pain, and ugly, but it works. If you are accessing the id dynamically with the $Component variable, e.g.

    {!$Component.thePage.theForm.thePanel}
    

    obviously you cannot double-blackslash escape without doing some javascript string replacement, but that’s even uglier.

  3. The easiest and seemingly best solution is to just pass the results of document.getElementById to the $() method, which can take an HTML object as a parameter, e.g.
    $(document.getElementById("thePage:theForm:thePanel"))
    

    or

    $(document.getElementById("{!$Component.thePage.theForm.thePanel}"))
    
  4. Seems to work in every scenario.

This entry was tagged , . Bookmark the permalink.