Thursday, October 4, 2007

Rich ajax applications that do not break if javascript is disabled.

Always wanted to test if the client's browser has javascript disabled in their browser ? Sounding impossible ? Well, not anymore!

Ok, so as Web2.0 applications are increasing in popularity and we are all starting to enable a lot of clientside javascript in our web applications, especially the use of ajax extentions and the updatepanel, we also know how this is all going to break for users who have javascript turned off or whose browsers do not support javascript.

Now, lets be real, it's not very common nowadays for a useragent to not support javascript, all the big players support it well(IE, Firefox, Opera, Safari).

However what about users that have javascript turned off ? Personally, I don't want my applications breaking on potential clients who fall in this category and realistically, today, there is no way to test for sure if the client turned off javascript. Sure, I am aware of the HttpBrowserCapabilities class, specifically the EcmaScriptVersion property. However this is a pretty useless property to me in this usage scenario since it only tells me what version of javascript the users client browser supports. This is simple static information passed on by the clientbrowser when making the request.

What we need is to know "Is javascript turned off ?" Knowing this is important in today's applications because it allows us to gracefully exit, or provide a serverside alternative, a non script version of our page being requested.

As of this writing I have not found any clear answer anywhere, so i have invested a couple of minutes to come up with the following solution. It's quite simple and should be working 100% without breaking, telling us exactly what we are seeking. -->> Hey, you there making the request, do you have javascript enabled/disabled ?

The idea is to introduce a piece of js code when the first request is being made by the client. Particularly a piece of code that can tell us serverside, "yes, javascript is enabled", without any delay or rendering much content to the client.

<script type="text/javascript">
window.location.href
='http://weblogs.asp.net/Default.aspx?supportsjs=true';
</script>

if javascript is enabled, the clients page will redirect, but what if js is disabled ? this script wont do anything, so to address this, we will introduce a second piece of code as well :

<meta http-equiv="refresh" 
content
="0;url=http://weblogs.asp.net/Default.aspx?supportsjs=false" />

That's it. If js is disabled, this second line will kick off and postback. Perfect.

Still, we don't want to do this everytime. We want to do this for the first request only, so what we can do is set a serverside flag in session state. I don't really recommend using session state because I find sessions to be unreliable, but that's just me. You basically have no control on when the session recycles. My preference lies in the profile provider(which is going to persist the value in the database and in style), however for simplicity, i'm setting a flag in session state.


Update october 4th,2007 : Initially, as you have read above in this post, i was planning on using the meta refresh tag if js was indeed disabled on the client. It was also a useless effort, when I couldof just assumed js was disabled from the start and only enabled if the js script fired the postback. As you will note from Richards comment below, the meta refresh tag only brings other problems to the table as it can in turn be disabled invidividually by the browser and not only in IE or Firefox but opera has support for this too. Here is the updated code that checks for javascript without meta refresh tag getting in the way.

Following is the code :

<%@ Page Language="C#" %>

<script runat="server">

/*
do it in init, otherwise you cannot
set ScriptManager.EnablePartialRendering property
*/
protected void Page_Init(object sender, EventArgs e)
{
bool notSet = string.IsNullOrEmpty(this.Request.QueryString["supportsjs"]);
string url = this.Request.Url.OriginalString;
if (notSet && Session["supportsjs"] == null)
{
string queryStringKey = (this.Request.QueryString.Count > 0) ?
"&amp;supportsjs=" : "?supportsjs=";

string jsTesterScript = string.Format(
"<{0} type=\"text/javascript\">window.location.href='{1}{2}true'</{0}>",
"script", url, queryStringKey);

Response.Write(jsTesterScript);
Response.Flush();
}

if (Session["supportsjs"] == null)
Session[
"supportsjs"] = false;// default, assume false

// if our js code posted back,
// and we still hold default assumption,
// then client does indeed support js
// so update the session

if (!notSet && !(bool)Session["supportsjs"])
Session[
"supportsjs"] = true;
ScriptManager1.EnablePartialRendering
= (bool)Session["supportsjs"];
}

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<h1>outside updatepanel : <%= DateTime.Now %></h1>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<h1>Inside updatepanel : <%= DateTime.Now %></h1>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>

I have tested the above code to work flawlessly in IE, Firefox, Opera and Safari. I've enabled and disabled javascript in the browsers during testing and as simple as the code may seem, it works. This is indeed great because now your rich ajax web applications can cater nicely to all targets and not break in the face of who has javascript disabled.

7 comments:

  1. Internet Explorer has supported disabling META REFRESH by domain since v6. The NoScript plugin for Firefox also provides an option to disable this tag. A better solution is to assume that script is disabled until you see the script-initiated request.



    In fact, with script disabled, the UpdatePanel works even when EnablePartialRendering is true. The only problem is the number of intrinsic ASP.NET controls which only work if script is enabled - e.g. the LinkButton control.

    ReplyDelete
  2. Is it possible to check javascript disabled on Java enabled web application?

    As currently i am working in a project where we are planning to use Ajax as client is expecting richer interaction.

    ReplyDelete
  3. Hi Om... it is possible in Firefox (I'm sure you can do it in other browsers)



    You just go to File > Preferences > Content and check the box that says Enable Javascript

    ReplyDelete
  4. I am Sorry, the Above code is not working fine, if i disabled java script. one i disabled the java script and execute the same code in other window. then total page is posting to server. so, ajax is not working.

    ReplyDelete
  5. First of all ... sorry about my poor English grammar! ... and thanks dear Alessandro to share your great idea...



    I think this is impossible to build RIA and Dynamic contents without JavaScript and Flash!

    I can't imagine Web 2.0 without Frameworks, Libraries, Accordions, Tabs, Sliders, Multiple-level menus, Lightbox's, Carousel's, Form validators, animation effects and so on...



    But "Disabled JavaScript" In Web 2.0 slowly turns to another black-hole for developers! (just like IE6 and Microsoft itself! -- sorry I hate monopoly)

    and what freaks me out is Microsoft disabled JavaScript in IE8 by default !!!!!?!!!!!



    I always worry about my clients JavaScript status! ... specially one with lack of amateur web experience!



    Final word ... W3School summery = 95% of users have JavaScript enabled in 2008 & 2009 ... So I use my favorite scripts and don't care about 5 percent!

    ----

    Ohhh, your commenting form not working at all without JavaScript!!! ... I have to enabled my JavaScript :)))))

    ReplyDelete
  6. Your english is excellent. Thanks for the comment :-)

    ReplyDelete