Tallan's Technology Blog

Tallan's Top Technologists Share Their Thoughts on Today's Technology Challenges

Customizing the Default jQuery Selector Behavior

Thomas Oscarson

jQuery on its own is a great JavaScript library that makes a lot of tasks simpler and easier.  Although as easy as it is you may find yourself needing to work within a restricted scope and not constantly wanting to have to include the context for every selector.  This exact case happened on our project.  We had the need to change from supporting just a single instance of a rather complex user control with a large amount of JavaScript, to having several instances of this control on the same page.  The JavaScript for this control utilized jQuery selectors all over the code, making it fairly tedious to accomplish without some help.   To make things easier we needed to restrict jQuery to the specific container that holds the instance of the control that we are interested in.  Now one way to do that would be to simply pass the context into the jQuery selector.

So something like this:  $(‘myselector’) would become $(‘myselector’, context), with context = $(‘mycontrolscontainer’).

Now that certainly would work, but with a large number or selectors in the controls JavaScript it can take quite a long time to replace all of these.

Instead of changing every jQuery selector, we can instead create a private jQuery instance, that automatically uses the correct context.  First we need to assume that each of these controls on the page is limited to the scope of its instance.  Within this you need to define a new variable for the instance specific jQuery, lets call it $$:

var $$ = function (selector, context) {
        selector = getFullSelectorIds(selector);
        context = getFullSelectorIds(context);
        return $(selector, context);
    };

This function $$, takes in a selector and a context, just like the normal $ function, however it does some extra work, using another function “getFullSelectorIds” which takes in either the selector or the context.  Then it uses the output of that function to pass into the normal $ function, which behaves just as it always had.

function getFullSelectorIds(selector) {
        // Selector string (looking for id(s)), check for _elementId appended
        if (typeof selector == "string" && selector.indexOf("#") != -1) {
            var ids = selector.split(",");
            var len = ids.length;
            for (var i = 0; i < len; i++) {
                // Looking for id
                // _elementId is not appended, so add it
                if (ids[i].indexOf("#") != -1 && ids[i].indexOf(_elementId) == -1) {
                    var subIds = ids[i].split(":");
                    subIds[0] = subIds[0] + _elementId;
                    ids[i] = subIds.join(':');
                }
                // _elementId is already appended or not looking for id in this one, no change
            }
            selector = ids.join(",");
        }
        return selector;
    }

The “getFullSelectorIds” function is the part that is special and will vary depending on your needs.  For our project we append a certain string to the end of all the IDs in the control.  This allows the IDs for the same part of each control instance to start with the same ID but end with the control specific one.  What we do here is append the _elementId string to any selectors that are string types, which are selecting based on ID’s (evidenced by the string containing “#”).  We also handle the  case where you have a comma separated list of selectors (that may be a mix of IDs, classes and others).

Now that we have the $$ function and the getFullSelectorIds function (which does all the real work), we are still not quite done.  Currently our $$ function is missing a number of nice jQuery functions.  To copy all of them over into the $$ we need to do the following:

$$.fn = $$.prototype = jQuery.fn;
jQuery.extend($$, jQuery); // copy's trim, extend, find, etc to $$

What this does is copy the jQuery prototype into the  prototype of $$.  Now the last step is to use it.  To use it all we need to do is replace any instances of $ with $$ and we are done.  Of course you can still use the regular $ function anywhere you want with no change to its functionality, or when you need to be scoped to within a specific control, just use that control’s $$.

Tags: JavaScript, jQuery,

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

\\\