Thursday, March 31, 2011

jQuery selector for .net controls




I guess everyone that developed in ASP.Net came across the annoying problem of selecting server elements by id.
The problem is the server controls render id's in a way that they will always be unique and they look like this: "ctl00_txtName"
which is ok, because by w3c standards elements must have a unique id.


But… when we want to select that type of element with the function getElementById
we run into a dilemma, make the code ugly and write getElementById("ctl00_txtName");
Or… place the JavaScript code inside an aspx page and write:
getElementById("<%= txtName.ClientID %>")


Even though the second option is the popular one, I didn’t like any of them. 
I used to render (from the code behind) all the id's I needed as some kind of JSON object and then I could still place all of my JavaScript code in .JS files. (where it belongs!!!)
Anyway… since the wonderful thing we call "jQuery" entered our life the whole client scripting experience became much nicer so why would this ancient problem be any different?
It shouldn't! There is a nice jQuery solution for this too.


Just to be clear this is not my original idea, I came across it at sometime and it can probably be found in some form or another on the web. 


So what is the solution? 
Using a simple jQuery selector of type "ends with" we can construct a very simple but useful function for selecting .net controls.


Anyway the function goes as follows:

function $$(id, context) {
    return $("[id$=_" + id + "]", context);
}
this selector selects all elements with an id attribute that ends with
"_theId" this will work for the example Id I gave earlier "ctl00_txtName"
if we were to call the function as so:  $$("txtName") we would indeed receive 
the element we wanted


But… there is a chance that we would also receive this element: 
"ctl00_secondForm_ctl00_txtName"
And for that reason there is another parameter to the function, the context
parameter is just passed to the jQuery selector  as always, so he would only 
search for our element in that context, like so:
$$("txtName", $("#container") );


That really helps when you are not sure if there is more than one element on the page that has an id that ends with the name you are looking for, and also improves performance of the selector.


I know this function is not bulletproof but it is very nice to have. 
We can make it even nicer like so:

function $$(id, context) {
    var el = $("#" + id, context);
 
    if (el.length < 1) {
        el = $("[id$=_" + id + "]", context);
    }
 
    return el;
}
The added code makes the
function a little bit cooler but… 


it hurts our performance a little bit too… because we are now running 2 jQuery selectors
but I think it is worth adding.
in case your element is not really rendered with a .Net id and you got confused
or someone changed your code and now that element is a regular Html element
we would still want our client code to run and not have to start changing it...
so I think it’s a nice addition.


Now to make our code even nicer we could add the function as a custom function to
jQuery like so:

$.fn.GetByNetId = function (id) {
    return $$(id, $(this));
}
And now instead of: $$("txtName", $("#container") );
we could write:
$("#container").GetByNetId("txtName");
which is a lot nicer :)
a new great thing is that since .Net 4 we no longer need solutions like this! 
Since .Net 4 we can just set the new "ClientIDMode" attribute to static
and that's it, that element will have the same id in the client as it has on
the server.

So that's it I guess… hope this function will save you some headache and
make your code a 
bit nicer like it did mine.   :)
May the force be with you

No comments:

Post a Comment