The Silver Lining

Lessons & Learnings from a salesforce certified technical architect.

Salesforce: A better way to work with jQuery selectors and Visualforce Component Ids

with 24 comments

Irregular Expressions

I get very sad when discussing this particular topic. There are a variety of ways of get Visualforce component Ids and using them in JavaScript but all of them keep me awake at night. Srsly. A commenter on one of my posts got me thinking about how we can do this better and I’ve come up with a way that I think is great. Hopefully you’ll agree.

This post means that my older posts here and here are now retired in favour of this method.

If the world was on the brink of nuclear war with no clear path to peace what could you count on to save the day? Regular Expressions of course. If a meteor the size of Pluto was about to crash into Earth and Bruce Willis was too old to land on it and blow it up what could we count on to rid us of the troublesome rock. Yes that’s right, Regular Expressions. I think you can guess where I’m going with this.

jQuery has the ability to understand very simple regular expressions in it’s attribute selectors. The full documentation can be found here.

To solve our particular problem however the code is simple:

<apex:page>
    <head>
        <style>
            a,span{
                display:block;
            }
        </style>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

        <script>
           jQuery(document).ready(function($){
               $('#btn').click(function(e){
                   e.preventDefault();

                   console.log('The following element was found when looking for an id of \'output1\':');
                   console.log($('[id$=output1]')); /* Here's where we're grabbing the element. */
               });
           });
        </script>

    </head>

  <apex:outputText value="She sells seashells by the seashore." id="output1"/>
  <apex:outputText value="Peter Piper picked a pack of pickled peppers." id="output2"/>

  <a href="" id="btn">Click me.</a>

</apex:page>

The important part here is the selector $(‘[id$=output1]’) which says, “Find the id value that ends with ‘output1′”. This comes with a warning though! Do not duplicate the Visualforce Id that you give to your elements otherwise this piece of code will find all of them.

When I first wrote this post I used a selector extension library that gives you the full power of JavaScript-based regular expression but Ryan Fritts has rightly shown that the above will deal with 99% of use cases and is simpler. For those of you that need to deal with the extra 1% I’ve implemented a wrapper to regex selector as an example. It does exactly what jQuery is doing above and gives you access to the regex flags as documented here.

Thanks again Ryan!

Advertisement

Written by Wes

June 24, 2011 at 2:36 pm

24 Responses

Subscribe to comments with RSS.

  1. Woot. I inspired a revolution. I do like this although id extend it to return the jQuery object – as i can’t envision a usecase for just needing the component regex unless you’re querying it.

    function component(id) {
    return jQuery(‘:regex(id,\:’ + id + ‘([^\:]*)$)’);
    }

    Ryan

    June 24, 2011 at 3:12 pm

    • Although I wonder why extend it into regex. Is there a performance bonus over id$= ?

      function component(id) { return jQuery(‘[id$=:”‘ + id + ‘”]’); }

      Ryan

      June 24, 2011 at 3:16 pm

      • Performance-wise I’m not sure. The reason I’ve used this method is because of flexibility, this isn’t my only use case for this library so I need to be able to vary things like the regex flags.

        You are right though, I think it’s important that developers are aware that there are attribute selector modifiers, I’ll add something into the article.

        Wes

        June 24, 2011 at 4:03 pm

    • Yes you did 🙂 As you said you could extend it for convenience, this is just a demonstration of the core capability. You can for example give the regex context like with other jQuery selectors. I forgot to link to the creator of the regex selector in the main article, I’ll do that now but you can find out more here: http://james.padolsey.com/javascript/regex-selector-for-jquery/

      Wes

      June 24, 2011 at 3:45 pm

  2. Much easier to read and use. Double win.

    Richard Vanhook

    June 24, 2011 at 3:57 pm

  3. I’ve actually been looking at this and there is potentially a way to optionally extend this so it is usable in table/repeat where the id would match each row’s entry. This would allow you to pass a restriction (to a row perhaps) to limit result set.

    function component(id, restrictor) {
    return jQuery(restrictor === null ? document : restrictor).find(‘:regex(id,\:’ + id + ‘([^\:]*)$)’);
    }

    or

    function component(id, restrictor) {
    return jQuery(restrictor === null ? document : restrictor).find(‘[id$=”:’ + id + ‘”]’);
    }

    Ryan Fritts

    June 24, 2011 at 4:42 pm

  4. amendment – to properly handle omission of restrictor

    function component(id, restrictor) {
    return jQuery(restrictor === undefined || restrictor == null ? document : restrictor).find(‘:regex(id,\:’ + id + ‘([^\:]*)$)’);
    }

    or

    function component(id, restrictor) {
    return jQuery(restrictor === undefined || restrictor == null ? document : restrictor).find(‘[id$=”:’ + id + ‘”]‘);
    }

    Ryan Fritts

    June 24, 2011 at 4:48 pm

  5. What’s wrong with using jQuery attribute selectors?

    $(‘input[id$=SaveButton]’)

    Matt

    June 24, 2011 at 5:02 pm

    • Yip Ryan has highlighted this in the comments, I’ll add the option in to the post. The reason that I proposed it like this is because of my use case which requires the ability to flip the regex flags. In all honesty the attribute selectors should be the primary solution with the code in this post dealing with edge cases.

      Wes

      June 24, 2011 at 5:12 pm

      • I would still expose a general purpose function for consistent usage pattern and handling iterative components (repeat, table)… just normally not consuming the optional second parameter below

        function component(id, restrictor) {
        return jQuery(restrictor === undefined || restrictor == null ? document : restrictor).find(‘[id$=”:’ + id + ‘”]‘);
        }

        Ryan Fritts

        June 24, 2011 at 7:19 pm

  6. Nice solution. I’ve just been using class selectors personally instead of Ids. Not sure if selecting by id is faster than class, but regardless I like your clever approach.

    kenji776

    June 24, 2011 at 6:07 pm

    • Thanks dude 🙂 yeah selecting ids is much faster since it uses a special piece of functionality available in all browsers made for Id searching.

      Wes

      June 24, 2011 at 11:29 pm

  7. Oh man, that ends with selector is money!

    Can’t believe I lived so long without it!

    Jason

    June 24, 2011 at 7:43 pm

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

  9. […] Salesforce: A better way to work with Visualforce Component Ids and JavaScript « The Silver Li… […]

  10. I’ve long been a fan of doing the selector on the styleClass rather than the id, but this may be a tinge better.

    fractastical

    August 7, 2011 at 5:54 pm

  11. Good One !

    Abhinav Gupta

    September 3, 2011 at 12:13 pm

  12. Thank you so much. Works great 😀

    María Paulina

    September 20, 2011 at 11:22 pm

  13. Thanks! Save me a headache!

    corycowgill

    October 10, 2011 at 6:12 pm

  14. […] Each form in Visualforce land carries around its own copy of the entire viewState, which makes it likely a behemoth. Be very careful to declare your variables as transient whenever possible and not to put multiple copies of a form on a page if at all possible. Elements have nested crazy ids that are difficult to work with (but can be accessed via this method). […]

  15. […] In preparation you may want to read this article on VisualForce and JavaScript. […]

  16. […] expressions can return you the ID of the top and bottom button in one line. More information here. Share this:EmailPrintTwitterFacebookDiggRedditStumbleUponLinkedInLike this:LikeBe the first to […]

  17. I tried using your technique to show/hide text using a mouseover and mouseout without success. Here is the code:

    var j$ = jQuery.noConflict();
    j$(document).ready(function(){
    j$(‘[id$=hideshow]’).mouseover(function(){
    j$(‘[id$=description]’).hide();
    });
    j$(‘[id$=hideshow]’).mouseout(function(){
    j$(‘[id$=description]’).show();
    });
    });

    Table

    Brian2000

    September 27, 2012 at 3:38 am

  18. This is awesome! So clean!!

    Ty

    April 24, 2013 at 8:05 pm


Leave a Reply to Jason Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: