Wednesday, September 24, 2008

Migrating to jQuery

About a week ago, my boss came to me and asked me to do add some new UI features to an existing interface.  Based on the request, I asked if I could use jQuery since I know the time it would take me to do the request with it versus without it.  I was allowed to do it as long as I provided some form of training on it.  Simple enough.  As I was updating the site, there was a few things in it that required me to have to fully update the entire site to jQuery and go away from its old ways.  Because of this, I thought it was be practical to provide a short post on some of the finding and conversions I had to do in order to go from standard, traditional JavaScript (i.e. document.getElementById()) to jQuery.

 

Why did I have to upgrade?

Before I get into the conversions, I think I should provide some details as to why I opted for an upgrade and not just add jQuery and do just what I was tasked to do.  The primary issue was that the existing JavaScript code had it's own $() function to take the place of document.getElementById().  Below is the $() function:

function $(x){
    return document.getElementById(x);
}

This, similar to that found in Prototype, caused some issues when I added jQuery to the mix.  Because of this, I could either update this function and all of the items that are calling it or do more work and remove the function and just convert everything to jQuery.  For consistency sake, I decided to do the latter.  It was a bit more work but it is better in the long run (and helped me confront all of the elements I needed to convert too).

 

Conversion Steps:

In order to go through with the conversion, the following steps were done:

  1. Adding the jQuery references to the appropriate pages.
  2. Comment Out/delete the existing $ function
  3. Replace all document.getElementById and existing $ calls.
  4. Replace all value calls
  5. Replace NULL object checks
  6. Replace attribute calls
  7. Replace CSS and Class Name calls

 

Step 1: Adding the jQuery References

This initial step was very simple in that it only required me to identify the pages that required the jQuery.js file to be added.  Since the web site that I was updating used ASP.Net Master pages, this made this step extremely easy.  After adding the simple <script> tag, I was ready to move onto the actual conversions.

 

Step 2: Commenting Out/Deleting the Existing $() Function

In order to ensure there is no conflicts, the existing $() function had to be renamed or removed.  In order to keep consistent, I deleted it.   By doing such, there would not be different ways to access document elements.

 

Step 3: Replace all document.getElementById() and $() calls

This step was very easy as well.  Since everything was already $("elementId"), a simple replacement was done.  I replaced $(" with $("#.  By doing such, it converted the old code to the new.  In order to ensure all calls were updated, I also replaced document.getElementById(" with $("# as well.

 

Step 4: Replace All Value Calls

Obtaining values in jQuery is a bit different than standard JavaScript.  Because of this, I had to do a couple things to complete this part of the conversion.  First, I did another simple replacement to convert .value to .val().  Afterwards, I went to each line that matches ".val() =".  At that point I manually updated the values to be parameters of the val() function.  It's not the best of ways but it worked for my small project.

 

Step 5: Replace NULL Object checks

This one is something I had to do a little bit of research into.  The jQuery function ($) always returns an object.  Because of this, we can not test any returned value to NULL.  The below example will return false every time.

if ($("#someElement") == null) {
    //code that will never get hit
}

In order to identify a NULL object, I had to check the object's value as shown below:

if ($("#unknownElement").val() == null) {
    //code that will get hit
}

The above example will return true if the object is NULL.

 

Step 6: Replace attribute calls

The code covered a number of select boxes and because of such, also addressed the selectedIndex property of such.  In addition, there was a couple of instances where I was looking at the text property of an option as well.  Traditionally, the code would look something like this:

var si = document.getElementById("selectBox1").selectedIndex;
var optionText = document.getElementById("selectBox1").options[si].text;

These values are not exactly as simple as obtaining a value for a drop down list in jQuery.  In order to obtain the selectedIndex property, I had to use the below code:

var si = $("#selectBox1").attr("selectedIndex");

After I had that, I had to do a similar thing for the options collection and the text:

var optionText = $("#selectBox1").attr("options")[si].text;

In this case, we are using the options attribute to obtain the collection, and then I was able to use call the text property as normal.

 

Step 7: CSS and ClassNames

The last item I had to tackle was addressing some CSS Class changes and typical style property changes.  In terms of CSS Classes, traditionally we would call an element's className attribute.  The issue with this methodology is that it does not work well with multiple classes on a single element.  It really give the user full responsibility of the classes.  While this isn't a bad thing, it can lead to a lot of possible bugs due to things being forgotten.  Thankfully, jQuery makes Class Names easy.

Any place that I had to add a Class Name, I updated the code to the following:

$("#someElement").addClass("className");

Any place that I had to remove a Class Name, I updated the code to the following:

$("#someElement").removeClass("className");

Lastly, any place that I checked to see if an element had a class, I did the following:

if ($("#someElement").hasClass("className")) { ... }

 

Conclusion:

While I covered what my conversion required of me, I know that there's a lot that I have not covered that many would have to do on a full conversion (i.e. radio buttons and check boxes).  There is a lot more that can be focused on in such conversions; however, I am hoping to provide a basic foundation for others to save some time in their conversions.  In addition to such a basis, I could see a small, simple application be created to do these conversions automatically through regular expressions as the means for replacement.  As more projects come up and/or I gain more time, I may do a more thorough guide or cheat sheet for such conversion or even one targeting converting from Prototype to jQuery or something like that.


kick it on DotNetKicks.com

3 comments:

  1. I was just reading about some jQuery stuff tonight on Chris Blankenship's blog post http://www.dscoduc.com/post/2008/09/24/jQuery-Goodness-for-BlogEngineNET.aspx. He mentioned jQuery's noConflict method http://docs.jquery.com/Core/jQuery.noConflict which might be something handy in your toolbox in the future. The method gives control of the $ variable back to whichever library first implemented it.

    Bill

    ReplyDelete
  2. Thanks Bill. I saw that when I was doing my conversion and for some reason I couldn't get it to work and my project didn't allow me the time to explore it more. I'll make sure to dive into it more in the near future and see if there's anything special that has to be done to use such.

    ReplyDelete
  3. I've used jQuery's noConflict method on a couple of my sites. The trick was to call noConflict before any other javascript libraries were included on the page.

    ReplyDelete