posts - 1234, comments - 293, trackbacks - 1, articles - 5
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

jQuery Intellisense in Visual Studio

Posted on 2008-05-05 22:41 linFen 阅读(...) 评论(...) 编辑 收藏

Jeff King, who's one of the program managers in the Web Tool Division and who focuses on the JavaScript editor, has posted about another byproduct of the Visual Studio hotfix I mentioned a few days ago. Jeff's post talks about how you can make Visual Studio's JavaScript Intellisense work better with jQuery. Previously working with jQuery got you - well, nothing because the the Intellisense parser didn't properly parse the jQuery source file and so failed to produce any Intellisense for anything in the jQuery library. The problem is that jQuery is basically one big function and since it failed to parse - you got nothing <g>.

The hotfix apparently works around the problem parsing jQuery and so you can get some Intellisense out of the box and with a wee bit of marking up the jQuery code you can now get some pretty useful Intellisense from jQuery in the JavaScript and ASP.NET Html editor. Jeff shows a small example of how to fix up jQuery functions by adding Visual Studio documentation with a suggestion of marking up the full jQuery library.

While I don't think I'd want to add VS specific comments to all of jQuery's functions and keep up with it for each of the frequent new releases of jQuery, I think adding a single single comment to the main jQuery function itself is probably worth it and it provides a pretty good payback for little effort.

If you don't do anything and leave jQuery.js as is you only get some limited supoport. What's new is that the parsing doesn't fail and because of it doesn't break parsing of other JavaScript files. In addition you can now do the following slightly non-standard jQuery activation and get Intellisense:

newJquery

Note that the new operator is required to make this work. Generally the jQuery function is called through its static function  (ie. without new) but that doesn't work by default.

In addition you also get Intellisense on the static object instance (not the function of jQuery) so the following also gives you Intellisense:

$.ajax( {
       url: "callbackPage.aspx", 
success: function(result){alert(result);}
} );

and you get Intellisense on the $ (same as jQuery) instance.

To get the static function to work you can make at least one small modification to jQuery.js. If you modify jQuery.js and only change the jQuery function definition (at the top of jQuery.js) like this:

var jQuery = window.jQuery = function( selector, context ) {    
    /// <summary>The jQuery object is actually just the init constructor 'enhanced'</summary>
    /// <param name="selector" type="var">Document selector. 
    /// (examples: "Element","#Id",".cssClass","#divMessage,#divError",DomElement,jQueryObject)
    ///  </param>
    /// <param name="context" type="object">Object scope of any code executed with jQuery functions</param>
    /// <returns type="jQuery" />
    return new jQuery.prototype.init( selector, context );
};

You get this Intellisense at the first level of jQuery usage which is the most common usage scenario:

 jqueryIntellisense[5]

Note that the single change addresses both jQuery and $ function usage.

You also get the comment information:

jQueryFunctionDocs

Most jQuery functions also return a jQuery object as a return value so you can chain operations, but even though those functions return jQuery objects that Intellisense now understands, it has no way of knowing what the return value type is and so chaining does not work unless you modify each of the functions with the same small hack by adding a return type as Jeff suggests in his post. It's simple enough to do if you find yourself chaining certain functions all the time. Just add the <return /> comment and you're done.

Note that as you drill into functions, parameter info is often not all that useful - unless you annotate - because jQuery mostly takes object map parameters that allow optional parameters to be passed and those only show up as a single object parameter. For example:

JsIntellisenseSyntax

is not terribly useful given that you can specify 15 or so optional parameters in the 's' map... you'll still need to consult the documentation to find all of the ajax() function flags, but this is certainly not Visual Studio's fault. Thankfully jQuery is well documented with easy to find documentation and examples.

Note that in order to get the basic VS Intellisense to work on any function you only need to add this below the function declaration:

    /// <returns type="jQuery" />

So if you want to be sly about this just cut and paste this line into a few of the core functions you use a lot (like filter, find, each etc.)  and that return a jQuery object for chaining and you're a long way to getting useful Intellisense functionality for a few minutes worth of work.

It'd be better if this was more automatic, but even so this is a welcome fix that improves usability with jQuery quite a bit especially if you're new to it and its many function parameters. At the very least adding the above to the jQuery function itself brings a sufficient payback during development.  In production you probably deploy the packed version anyway so this doesn't affect production code in any way anyway.

A few thoughts on JavaScript Intellisense in Visual Studio

I just wish a little more work could be done to make consumption of JavaScript easier. Intellisense in Visual Studio is severely hampered by the fact that once you assign a function value to a variable you lose all use of Intellisense with the variable. Sticking with the jQuery theme here, the following doesn't do well:

var jCtl = jQuery("#divMessage");
var text = jCtl.text();
var val = jCtl.value();

In this code I'm reusing the jQuery instance rather than making calls to the function repeatedly, but as soon as I assign to jCtl all Intellisense goodness is gone even though the parser inheritently understands what jQuery() is and what it returns.

The parser understands this though:

var jCtl = new jQuery("#divMessage");    
var text = jCtl.text();

and WILL provide Intellisense for jCtl in this scenario. While this works here and it's functionally equivalent (although non-conventional), it's not always practical to declare a new object. In other situations you have no choice at all because results may simply be returned from a function and there's no way to fake the type with an explicit object declaration.

If I really need this functionality I've often temporarily added a type declaration to get Intellisense to work

// Temporary declaration - remove when done
var date = new Date();
 
// 'real' code in your script
dateString = date.toLocaleTime();

and while that works it's a hassle to add vars like that and remember to remove them. So much so that most of the time I don't bother unless there's lots of code against a complex type.

It sure would be nice if one could place a comment into the code to give a hint as to the type of the var with something like this:

/// <declare var="jCtl" type="jQuery" />
var jCtl = jQuery("#divMessage");    
var text = jCtl.text();

Better yet I would love to see the Intellisense parser figure out that the call to jQuery() returns a jQuery object and work off that. It seems given that Intellisense works on the function itself that this should be possible to associate the variable with the return type.

ASPX pages and Scripts loaded via Resources

One scenario that bugs me is that I can't force Intellisense to recognize script files that are loaded via Resources. If I have a control that loads its own resources the only way I can get Intellisense to recognize the script file is by adding a <script src="" /> reference into the page. Doing so however breaks my page potentially because the script file is now loaded twice.

I don't have a problem with having script files available in the design environment even if scripts will serve from resources, but I need some way to load the script for Intellisense.

JavaScript (.js) files have an option to include a comment that forces loading of files:

/// <reference path="../scripts/jquery.js" />

but unfortunately that doesn't work in an ASPX page, or at least I haven't figured out to make this work.

The only way to get this to work is to add the ASP.NET AJAX ScriptManager to the page, but I'd like to avoid that given that it requires the whole configuration of Atlas as well as ASP.NET AJAX client libraries loading which I don't need.

There really should be some other mechanism to allow letting Intellisense work with resource based javascript files in an ASPX page.