Practical ASP.NET

JavaScript and AJAX in ASP.NET: Not Quite Ready for Prime Time

Client-side debugging is better, but IntelliSense still has a few issues to be worked out.

The promise of AJAX, for me, is the possibility of a new paradigm for Web applications. In this paradigm, the user enters a URL to request a page. Once that page displays in the browser, the user interacts with the page without posting back to the server. Instead, client-side JavaScript code calls Web Services to retrieve and save data.

Back in an article on the beta of AJAX for ASP.NET ("Build Smart Web Apps With Atlas" in the March 2006 issue of Visual Studio Magazine), I said, "There's still much to be done before Atlas is ready for prime time. Debugging is awkward, and the lack of IntelliSense support in Source view means that coding is error prone."


Those two specific problems have been addressed in Visual Studio 2008 and .NET 3.5 -- sort of. Client-side debugging is much improved in Visual Studio 2008. But IntelliSense support for JavaScript is only "sort of" better. The good news is that IntelliSense will now show you all the HTML objects on the page.

Not Ready for Prime Time
The bad news, however, is that IntelliSense won't show the ASP.NET objects on your page because, of course, the HTML tags for these controls aren't generated until runtime. It's not really a satisfactory solution: The only way in JavaScript to access an ASP.NET control is by passing the name of the control to a method that will return a reference to the ASP.NET object, which isn't a reliable solution.

There are two methods you can use for retrieving an ASP.NET control at runtime: the DOM-standard getElementById or Microsoft's $find extension. This is the code that you'd use with the getElementById method to retrieve a control with its ID attribute set to TextBox1:

var textb = window.document.getElementById("TextBox1");

Using $find is more forgiving (it will search both the ID and name attributes of a tag, for instance) but only works reliably in Internet Explorer. With the $find method, you pass the name or ID of the control you want and the container you want to search in (typically, window.form1). This example retrieves the control with TextBox1 in either its ID or name attributes:

var textb = window.$find("TextBox1", window.form1);

Once you've retrieved the object, you can set or retrieve the control's value property:

textb.value = "Hello, World";

While these methods work, they're hardly satisfactory. Since you're passing a string to these methods, there's every possibility that you'll spell the name of the control incorrectly when you write your code. This is the worst kind of bug: a problem that you won't discover until that line of code executes.

Working with Naming Containers
However, the code does work in a wide variety of scenarios: if the control you're searching for is sitting directly on the page, is in a panel, or even if it's in a View control. Unlike the server-side FindControl method (which I covered in my column "Using Findcontrol and PreviousPage with Master Pages"), this client-side code also works even if your page is based on a Master Page. However, if the control you're searching for is inside a naming container like a FormView, then the code will fail.

To find a control inside a naming container, you'll need to pass the fully qualified name or ID attribute for the control you're looking for. For a text box named TextBox1 inside a FormView named FormView1, any of these lines of code will find the control:

var textb = window.document.getElementById
   ("FormView1_TextBox1");
var textb = window.$find("FormView1_TextBox1", 
   window.form1);
var textb = window.$find("FormView1$TextBox1", 
   window.form1);

This code will fail, however, if the template in the FormView that contains TextBox1 isn't being displayed when the code executes. Some error handling to check that the control was found before setting the control's value property will handle that problem:

if (textb != null)
{
   textb.value = "Hello, World";
}

However, this code will also break if:

  • The name of the containing control (the FormView) is changed.
  • The containing control, with all of its child controls, is moved inside some other containing control.
  • Microsoft changes the format used when generating the ID or name attributes of HTML controls inside a naming container.

And, to repeat an earlier point, you won't get a compile time error in any of these scenarios until you execute the offending line of code in the browser. And, if my experience is any guide, it will probably be an end user who discovers the problem.

About the Author

Peter Vogel is a principal in PH&V Information Services, specializing in ASP.NET development with expertise in SOA, XML, database, and user interface design. His most recent book ("rtfm*") is on writing effective user manuals, and his blog on technical writing can be found at rtfmphvis.blogspot.com.

Reader Comments:

Fri, Jun 20, 2008 Peter Canada

I haven't used Expression Web 2.0. My assumption has been that, as a programmer rather than a designer, Visual Studio will serve me betterbut that's just been an assumption. Part of the problem is that not only have I invested a bunch of time in figuring out how to use VS's various productivity enhancements, I've also spent some time learning how to create Add-Ins and how to exploit the VS object model. So I've got a big investment in VS that holds me there.

Thu, Jun 19, 2008

Have you tried AJAX with Expression Web 2.0 and if yes what do you think?

Tue, Jun 17, 2008 Peter Vogel Canada

I obviously touched a nerveprobably the result of a server-side programmer working in client-side code. First, I should have been clearer about $find.
I only referenced it because I think of $get as a shortcut to getElementById. Having complained about getElementById it didn't seem worthwhile to repeat those complaints about $get.

I'll move to SilverLight when there are more sites using it that aren't sponsored by Microsoft.

Adding client-side code to the page from the server is a good idea (it's what I do, as a matter of fact) but that means giving up compile-time checking of my JavaScript syntax in order to get compile-time checking of my object names. It hasn't been a great trade-off in my mind.

But the best solution was the one about using inline server-side code to resolve the ClientId (wish that I'd thought of itand given my time in classic ASP, I should have. Dumb, dumb, dumb). It certainly takes care of the container problem and it even checks the object reference at compile time. It would be nice to get IntelliSense support when entering the control name but we can't (yet) have everything. Thanks for that.

Wed, Jun 11, 2008 Graham California

I'm surprised that Visual Studio Magazine would publish such a dreadful article. We've come to expect more from VSM. Peter Vogel addresses fundamental issues about which he is clearly ignorant.

Wed, Jun 11, 2008 Anonymous Anonymous

I'm surprised that Visual Studio Magazine would publish such a dreadful article. We've come to expect more from VSM. Peter Vogel addresses fundamental issues about which he is clearly ignorant.

Tue, Jun 10, 2008 Andy Anonymous

A more robust way to retrieve a control is to use the "" syntax.

var txtFld = $find("");

This will no break in the ways that the author mentions.

Tue, Jun 10, 2008 Fallon Massey

Just dump that crap and move to SilverLight. Sure it's not totally ready yet, but to continue to use Javascript and HTML is like getting water boarded... it's painful and there's no upside(lol).

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above