Getting jQuery Goodness into ASP.NET AJAX - Take II
So clearly I am obsessing about getting jQuery features into my WebForm applications. I would seriously love to see the following added ...
- A more powerful selector. Finding elements by ID (ala $get) in an ASP.NET page is usually pretty awkward because the ID values isn't known until runtime. This alone causes many people problems. Unless I am mistaken the next version of ASP.NET AJAX will include a selector to find items by class name as well, but I have not heard anything for supporting more advanced stuff like ...
1: // good ...
2: var alternatingRows = $select('TABLE TR.alt');
3: 4: // better ...
5: var alternatingRows = $select('TABLE TR:odd');
6: 7: // best!
8: var alternatingRows = $select('TABLE TR:nth-child(odd)');
- A more fluent programming model. jQuery seriously embraces the 'find some elements and do something with them' mantra. And they make it really simple to do - if you want a zebra striped table that also supports the row hover effects, all you need to do is the following ...
1: // add the row hover highlighting
2: $("TABLE TR")
3: .mouseover(function() {$(this).addClass("highlight");})
4: .mouseout(function() {$(this).removeClass("highlight");});
5: 6: // add the zebra striping
7: $("TABLE TR:odd").addClass("odd");
8: $("TABLE TR:even").addClass("even");
- JavaScript only plug-ins. There is something like 6.5 Bazillion jQuery plugins. Seven new ones have already been created since you last checked your email. I have to believe that part of the reason there are so many of these floating around is because they are so darn easy to create and distribute. Plus if you crack some of them open it is almost sickening how simple they are. As a matter fact you could create a zebraStripedPlusRowHighlighting plug-in from the above code snippet and then just do the following to apply it to all of your TABLE elements
1: // add zebra striping and highlighing to all my TABLE's
2: $('TABLE').zebraStripedPlusRowHighlighting({'hoverClass':'highlight', 'oddClass':'odd', 'evenClass','even'});
So by this point you might think I get a kick-back or something from jQuery for pushing this stuff so hard, but truly I am not. Its just that I get a little jealous browsing the jQuery plug-in page and seeing all of the cool stuff that I can't use.
And so I laid out my approach to bridge this gap between ASP.NET AJAX and jQuery. My first thought was to simply port some of the most useful jQuery features over into some sort of JavaScript shim. But after thinking about this I am not sure if it this is so great either. Play this forward: say I was able to get a large number of the jQuery features into the shim - what does this really get me? I still can't use any of the jQuery plug-ins without porting them over too. And I would think it would be practically impossible to ever get to a point where there is feature parity between my shim module and jQuery. And suppose I could reach that point - this new extension library would be most likely just as big as jQuery is in the first place. Which was one of the reasons I stated previously for not using jQuery - I didn't want the bloat of 3 JavaScript libraries {ASP.NET AJAX, AjaxControlToolkit, jQuery}.
So I think I need to do some more work here thinking this through.
- I am sort of ashamed to say this, but I never really looked into what kind of overlap there is between the 3 libraries. I assume there is quite a bit between XmlHttpRequest, Animation, DOM manipulation, Browser detection, selectors, data types, helper functions, etc ... But I have not actually looked into seeing what exactly this overlap is and if there would be a way to minimize some of it. Say if I could get jQuery selector without any of the other stuff ... jQuery lite?
All this being said, I did take a look at some of the jQuery programming model fundamentals just because I was curious. And I learned more than a few things so I thought I would pass them along*.
* disclaimer: I am pretty new to jQuery so none of this stuff is gospel and correct me if you see something I missed.
The Wrapped Set
A core piece of the jQuery programming model is what is referred to as the wrapped set. This wrapped set is the collection of DOM elements that you wish to execute some operation (I believe jQuery refers to these as commands) on. jQuery's powerful selector returns a wrapped set that contains all of the DOM elements that match the provided selector. Once you have a reference to a wrapped set, you can execute some operation upon all elements within the set. So you can easily do stuff like this ...
1: // add the grid css class to all TABLE elements
2: $('TABLE').addClass('grid');
3: 4: // show the id of the INPUT element when it is clicked
5: $('INPUT').click(function(){ alert($(this).id); });
Chaining
The wrapped set contains a ton of useful methods. And most of them return the same value - the reference to the wrapped set. This allows you to chain commands together keeping the code very concise yet still very readable. The following example of adding highlighting to a TABLE uses this chaining.
1: // example that shows how calls are chained together
2: $('TABLE TR')
3: .mouseover(function(){ $(this).addClass('highlight');})
4: .mouseout(function(){ $(this).removeClass('highlight'); })
Updating my Shim
So, to continue my experiment of trying to get some of this stuff into my WebForms apps, I made the following changes to plug-ins I discussed in my previous post:
- I created a JavaScript class that is a stripped down version of jQuery's. It contains a collection of DOM elements and contains methods like ..
- add, get, remove, clear, each -> basic collection operations
- addClass, removeClass -> basic DOM operations
- blur, focus, mousedown, mouseup, etc... -> shortcuts for adding event handlers
- After I created the wrapped set class, I updated the $select function to return an instance of this wrapped set that contains all of the elements that matched the selector. I also renamed $select to $majax. So now you can do things like this ...
1: // attach all of the textbox elements and
2: // and apply the focus class when the textbox
3: // obtains the focus
4: $majax('textbox')
5: .focus(function(){ $majax(this).addClass('focus'); })
6: .blur(function(){ $majax(this).removeClass('focus'); });
Which would turn the background of all of the DOM elements that have the textbox css class to yellow (via the focus css class) when they have focus. It would look something like this ...
![]()
- And finally, I changed the plug-ins to use my wrapped set prototype to add their commands to instead of the Sys.UI.Control class. This made a nice difference in how I was able to apply my plug-ins to a collection of DOM elements. Checkout the OLD and NEW syntax examples below.
1: // OLD:2: $select('#roundedPanel1, #roundedPanel2').each(function(e){3: // add the rounded corners (6 pixel radius) to the panels4: e.round(6);5: });6:7: // NEW:8: $majax('#roundedPanel1, #roundedPanel2').round(6);
And here is how the new RoundedCorners plugin is defined. The main changes are round function is attached to the elementSet prototype (this is the wrapped set class), the _round function operates on all elements in the current set and the _round function returns a reference to the wrapped set - allowing chaining.
1: Type.registerNamespace("majax");2:3: majax.RoundedCorners = function() {4: majax.RoundedCorners.initializeBase(this);5: }6:7: majax.RoundedCorners.prototype = {8:9: initialize : function() {10: majax.RoundedCorners.callBaseMethod(this, 'initialize');11:12: // attach the plugin to the elementSet class13: majax.elementSet.prototype.round = this._round;14: },15:16:17: dispose : function() {18:19: majax.RoundedCorners.callBaseMethod(this, 'dispose');20: },21:22: _round : function(radius) {23: // create rounded corners for each of the elements24: // in the collection25: this.each(function(){26: $create(AjaxControlToolkit.RoundedCornersBehavior, {"Radius":radius}, null, null, this);27: });28:29: // for chaining30: return this;31: }32: }33:34: // register the class35: majax.RoundedCorners.registerClass('majax.RoundedCorners', Sys.Component);36:37: // create the singleton38: $create(majax.RoundedCorners, null, null, null);39:40: // Since this script is not loaded by System.Web.Handlers.ScriptResourceHandler41: // invoke Sys.Application.notifyScriptLoaded to notify ScriptManager42: // that this is the end of the script.43: if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Where to Next?
Good question. So far the small jQuery-ish shim I created seems useful. Its 200 LOC right now its pretty small, but if I continue down this path it will no doubt grow quickly. So I am not really sure where I am going next - but I don't feel like giving up either.
How About You?
What about you? Are you a WebForms developer that is crushing over jQuery too? Do you have a problem using 3 JavaScript libraries - ASP.NET AJAX, the Toolkit and jQuery? How do you think this problem (if there is one) should be solved?
That's it. Enjoy!
Comments
I definitely know how youre feeling Matt. I found so much value in jQuery that I ended up eliminating the ScriptManager and ASP.NET AJAX entirely. That may seem drastic, but after creating a jQuery wrapper to call page methods, I simply couldnt justify keeping the bloat of the script manager on my pages any longer.
I was a big fan of ASP.NET AJAX and masking the complexity of hand-coding Javascript... up until the day I found jQuery.
Gday Matt - I might be missing something, but in answer to your first point on "A more powerful selector", do you get around not knowing ASP.NET IDs beforehand by just adding classes to your controls, and then identify them by class to JQuery? I tend to do this and leave the auto-generated IDs alone.
Perhaps youre not so much asking a question as making a point...in this case, disregard this post :-)
Cheers, Thomas
I think the answer is to drop the MS Ajax stuff altogether, I really like the asp.net MVC framework, JQuery works great with it. Once you start down that path I think you will start looking at the webforms model as being super constraining.
Im right there with you. Im not a fan of the AjaxControlToolkit but I certainly feel the pain of adding both MS Ajax and the weight of an additional library.
I think you may be onto something with this though. I hope youll keep going with it and see where you end up.
I hear you Matt. I am so wanting to use the jQuery libs but dont know how wise it is when I am using the MSAjax tools. Have you dug into the jQuery AJAX plugins? If so what do you like/dont like about it? I started toying with it and was thinking of dumping MSAJAX, especially since it seems as if Microsoft has put it on the back burner for MVC and Silverlight. We havent seen anything from the toolkit team since Feb. WTF? The only thing we have seen is from you. Also, whats in your AJAX toolkit? What are some of your favorite tools/addins/plugins? That would be a cool post.
I never used jQuery yet. But it seems that its really simple to use. The small version of jQuery (slimJQuery?) can we download it somewhere?
Hope you can make also an example page of (every?) option there is in jQuery. So i and other people know what you can do with it. If there is all ready a page like this please let me know.
Thanks
Bjorn
Its simple - drop asp.net ajax and the Toolkit :D. Most of the controls in the toolkit are simple animations.
And the rest are covered by jquery plugins.
Great work, Matt! Good to se there are more and more asp.net developers interested in jQuery. Reading all those blogs out there one could think its a matter of a design only.
Im using jQuery intensively on a current project and adding some enhancements to my blog these days. All together with asp.net ajax.
I think now you have a simple vision of what should be done.
I think starting with cloning jQuery style of code into ASP.NET AJAX like chaining and apply same chaining applied in jQuery. Then step by step move into different features. or provide some of the features then move to demonstrate these features using plugins.
Myself, Im waiting to have sometime to start to move on your road to apply some of the features I liked in jquery.
Anyway, good luck and keep on that road, it can be done, Im sure it can be done.
Putting jQuery into ASP.NET would be great, but I think there are some flaws with ASP.NET AJAX that would be difficult to address. Element IDs is a major problem. Another is the amount of code needed to do anything client-side. That last code sample is very big compared to a jQuery plugin:
jQuery.fn.debug = function() { return this.each(function(){ alert(this); }); };
@Carlito -
Removed ScriptManager all together? I know this sounds weak, but I dont know if I can live without the UpdatePanel for handling stuff like sorting/paging through a GridView. Its just so easy.
@Thomas -
Yea - I guess my point was that its a bit ironic that with $get you can only retrieve elements by ID - because this is the one value you dont know.
@Daniel -
Yea, I havent tried it out just yet, but I am guessing that I would love the MVC/jQuery combo. But the problem is that it just doesnt make sense for our business to rewrite our forms on top of MVC - way too many pages plus we just moved from 1.1 to 2.0 at the begining of the year. If I had to guess our next major move is at least 2 years away. But in the mean time I would love to find a way to use some of the jQuery stuff (either via a shim or just straight using it) in my app
@Doug Wilson -
I have mixed feelings about the Toolkit. I love controls like the TabContainer, Calendar, ModalPopup, DropShadow ..., I just wish there were more people building and distributing them.
This is something I would love to get figured out - so I am guessing I wont be giving up on it anytime soon.
@Jared Roberts -
Wow - lots of good stuff in your comment.
- I agree, the Toolkit seems to be getting stale. But I know it hasnt been forgotten (Rob Conery just posted a bit about using some of the Toolkit controls in an MVC app. I havent watched the video, but I am guessing they are doing something similar to what I am doing here (explicitly calling $create to initialize the control). So I am hopeful these teams are getting together and figuring out how to make some of this stuff easier (both authoring the controls and distributing them).
- Good idea for a post. I will put that on the list.
Bjorn van der Neut -
Sorry Bjorn - I just made up jQuery lite. I am not sure if it exists.
@sirrocco -
Is that what you have done? I dont want to sell the Toolkit short though. Its got a lot of good stuff in it that I dont want to lose.
Its a classic Tyranny of Or for me. I dont want to choose - I really want a nice way to use all three ;)
Hi @Janko -
You have a killer blog. I was looking at your form highlighting example over the weekend. And its just another example of the things that I want to do. Keep it up.
So you use ASP.NET AJAX plus jQuery, but no Toolkit? Have you looked into how much overlap there is between these 2 libraries?
@Hi Muhammad -
I think thats the route I will end up taking. Thanks for the feedback.
I dont think theres much extra bloat in including even the entire jQuery core on top of MSAJAX. The two play nicely and the jQuery core is only 55KB minified; 15KB when using IIS compression. Compare that to what the MSAJAX library outputs for a simple AjaxToolkit control... yikes.
Is there a link to the code on this page?
I have removed the toolkit and been working with just msajax and jquery, they seem to work fine together for me. If you look at the number of webresource calls msajax and other aspx controls make, jquery is not really the problem, if you are worried about bandwidth.
Jquery rocks... Ive even started to prefer doing stuff with it rather than server-side code, cause its much less code. Its even got me thinking about the possibility of a viewstate-free and postback-free world, just using MS ajax web services and page methods, and of course jquery.
@Dan Goldstein -
Yep the ID thing makes some tasks a little more difficult than you would like, but I think some of this could be addressed by using class and tag selectors.
@Ryan -
That is interesting. I am pretty sure we have some pages with VIEWSTATE larger than 15KB ;). I really need to look at this. Maybe I wouldnt be so in love with the Toolkits TabContainer/Calendar if I saw the size of the scripts it is pulling down.
@Mcbeev -
Sorry no - not yet. I can put it up later today.
@Chris -
Another vote for ASP.NET AJAX plus jQuery and no Toolkit. Interesting ...
And a WebForms world with no viewstate and postbacks - so how do you envision handling stuff like server side paging and sorting for a typical grid? Use a page method to send the data across the wire and then build the DOM on client via one of jQuerys templating plugins? Build the markup on the server? Something else?
I was playing in a project with jQuery and AjaxToolkit. Finally I just removed the jQuery reference, and made all the JS using the AJAX Client API. I done this because the usage of jQuery increments my response time, and I couldnt remove the ScriptManager because I use DotNetNuke :(
I think that jQuery is VERY powerful, but cant live together with the AJAX Toolkit, I dont like have different ways to do the same, I found that is something wrong with that overlapping.
I like the idea of only leave the selector and extension capabilities of the jQuery removing some overlapping.
All my best,
Thanks, Matt! Actually, I am using toolkit as well. Right now I am exploring all the benefits I can get by combining those three technologies.
Surprisingly for me, they work perfect all together. Honestly, I expected to have at least some problems :)
+1 jQuery
No need for MS Ajax. What does MS Ajax do that you cant do or already have with jQuery (including a far superior Validation/Form library)?
Although as you can see above, MS has done a good job of making it difficult to use what the rest of the world finds easy to work with.
http://www.infoq.com/news/2008/06/pingdomJSSurvey
Using jQuery to Consume ASP.NET ajax:http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/
"By using jQuery to call the web service directly, we’ve eliminated over 100 KB of JavaScript and three extra HTTP requests. The ASP.NET AJAX client side framework accounted for over half of the original example’s total download size, and those three extra HTTP requests unnecessarily delayed the progress indicator.
That may not sound like much, but it’s significant. When it comes to loading speed and responsiveness, users do not perceive changes linearly. Fractions of a second make the difference between a site that feels sluggish and one that appears responsive."
There is an asp.net 3.5 sample to try it out yourself...
Hi, i am a big fan of asp.net ajax and the ajax control toolkit. I havent found much of a need for jquery yet but at times i find javascript programming quite tedious so i may look into it in the future. I have the same problems as you with switching to jquery entirely in that i have become too dependent of the updatepanel.
I have also never found the need to do much more than what is already in the toolkit but id imagine you could simply create server controls which replicate the functionality in jquery. This makes it trivual to switch from the toolkit to jquery.
However it seems the updatepanel is the thing holding me back and i wouldnt know where to start in creating this functionality in jquery. I would suspect that even if i did come up with something it wouldnt be as simple as wrapping a listview in an updatepanel.
I dont think theres much needed to make asp.net ajaxs javascript programming simpler, definately a better selector (i preferred $select instead of $majax) but you seem on track and i wouldnt give up.
After you jump into it, this turns out to be pretty easy. Since most of your styling should be in external CSS anyway, all you need to build on the client side is the basic semantic structure of your table.
Ive got a sort of live example of doing that here: http://WinScrabble.com
When you run a search there, it calls an ASMX web service with jQuery, renders the resulting JSON array into a table, then applies the jQuery tablesorter plugin to that table.
I used to have an UpdatePanel there, but had to remove it because the bulk was killing my initial load times. When I replaced it with jQuery, the average time for a 7-8 letter search improved by over 400%.
So, chalk up another vote for ditching the toolkit and going jQuery all the way.
Im using MS AJAX Toolkit + jQuery. Why Toolkit? Because of some controls like calendar with their nice efects (changing month/years animations) + some other behaviours (FloatingBehaviour, ResizableControlBehavior). I didnt spend time to re-code those efects with jQuery.
Good part about jQuery is that works nicely with other JS libraries like Toolkit + its powerful and small. If you use it compressed its only ~30kb, so why bother stripping it down to a lite version? Its much simplier just to use/deploy official release (easy to upgrade later).
Matt I really like your approach. We found the need to abandon the toolkit and roll our own ajax plumbing.
I really see some heat in the comments regarding to go through the pain or just use jQuery, I think its a nice approach for nailing the javascript but maybe endup with a waste of time, as jquery plugins increase by the second.
I prefer the jQuery way. Good luck and really waiting how long can you go with this, might end up with something really cool.
Matt,
You really need to make the leap to MVC.
I know its extremely hard to justify if you have a large code-base, but the benefits are endless.
JQuery is just one of the libraries youll be able to use. The freedom to control the xhtml output is superb.
Make the leap, you wont be disappointed. I just did.
Kevin
@Walter -
Interesting – I am not too familiar with DNN.
@Dave -
Hi Dave – I was hoping I would hear from you ;)
Yea – I can see how that would work. I see the MVC guys have some nice helper functions for doing stuff similar to this. Have you fooled around with a Table helper functions? Or is that overkill? What about server side paging and sorting – how you sketched out how that might work?
What was it with the UpdatePanel that was causing the perf problems?
@Amr Elsehemy -
Yea, Its kind of fun seeing how passionate us computer geeks can be ;)
@Kevin Jensen -
If it was just me making the decision I would. But we just moved from 1.1 to 2.0 and rewrote every page along the way and I don’t think I would be able to justify the move.
Just curious – did you rewrite an existing application? How large was it and how long did it take you to get back to feature parity?
@Matt
I think some sort of table helper JavaScript library might make sense for larger projects. I believe there are several HTML templating plugins for jQuery which might handle the job pretty well.
For the relatively simple application in the site I linked above, the table generation function is only ~10 lines of JavaScript. I have a function that takes a JSON array as a parameter, does an innerHtml = on the tables container, builds the table as a string, and drops that into the container with innerHtml.
For server side paging and sorting, I would add parameters to the web service and handle them appropriately.
Im not sure exactly why the UpdatePanel was so much slower. I suppose all of the overhead of the page life cycle hurt significantly. I believe partial postbacks are also slower for tables because the client framework doesnt use innerHtml to render the result.
Heres a blog post with an example of the HTML building routine I was talking about:
http://encosia.com/2008/06/26/use-jquery-and-aspnet-ajax-to-build-a-client-side-repeater/
The "ugly" technique is almost verbatim from the WinScrabble site I linked above.
After having a frustrating end to a project that dealt majorly with ASP.NET AJAX and its infamous Update Panel intricacies, I decided to collect my end results and evaluate on how to improve quality of the tools I use and the overall approach I take to create "Web 2.0" apps.
I had to do something about the bloated UpdatePanel and the way it performs! I started my project by putting an UpdatePanel in all my maintenance components and playing around with their settings. I had a total of 4 Update Panels in my page and it became awfully slow. I decided to dish out the UpdatePanels on my maintenance controls and use a combination of WebServices/JSON and also AJAX.NET PRO to return large DataSets. My application improved dramatically after doing so but I do question some of the functionallity behind ASP.NET AJAX framework.
Seeking for alternatives, I evaluated different JavaScript frameworks MooTools, DOJO, Prototype, and JQuery. Bottom line, I concluded that JQuery was the easiest, had an extensive community supporting it, and AJAX support is OK. There are tons of plug-ins and I now think back of how handful this library would of come in handy in my previous project. I hope that this library can grow even more in popularity amongst ASP.NET developers and hope to see some nifty plug-ins. I would love to narrow down to only using one JavaScript library and after a 2 day test drive using JQuery, I might have just found a winner. Aww the UpdatePanel seemed so promising!