Tuesday, December 30, 2008

ASP.net UpdatePanel Slow Performance compared to jquery Ajax

I guess this won't come as a surprise for most of us veterans who have been using UpdatePanels for a little bit. For those who don't know what UpdatePanels are or do, a quick intro - UpdatePanel is a control shipped with ASP.NET Ajax that Ajaxifies server side calls from any controls that are put inside it. You can set the EnableHistory attribute in ScriptManager to true and you get the built in history (Ajax back button problem) as well! It's all out of the box and can save quite a bit of development time only but it's slow as sh-t!

Let's look at a "case study" (that was my own project) -


Problem: Implement a "wizard" like functionality where the user steps through a number of questions presented one at a time.

Catch: Save answers to each question to the database as the user moves to the next question.

Bigger Catch: There must not be any page refreshes as user moves from one question to the next.

Insanely big Catch: Hitting browser's back button should take user to the previous question!

Two Ajax & Browser history solutions:


- ASP.NET Ajax's UpdatePanel with ScriptManager's EnableHistory set to True - UpdatePanel takes care of Ajax and EnableHistory attribute takes care of browser's back button.

- jquery ajax calls to a webservice with RSH (Really Simple History) - basically saving the answers (to the questions in wizard) via asynchronous jquery Ajax calls to some webservice. This takes care of stepping through the wizard and saving data without page refresh problems. Browser's history (back button) problem is solved by using RSH (Really Simple History) library.

Comparison of UpdatePanl ajax and jquery's ajax -


Performance comparison of UpdatePanel and jquery ajax: UpdatePanels suffer from some huge performance problems and can be ridiculously slow. As you see in the screenshot, 13 requests (yeah not a good number!) required 2MB. These requests are made by controls like DropDownLists, RadioButtons and Buttons, all wrapped in an UpdatePanel.
ASP.net UpdatePanel slow performance Ajax

RSH and jquery ajax implementation, on the other hand, is much faster! As you see in the screenshot, we got away with only 103Kb of data with 20 jquery ajax calls! Compared to UpdatePanel, this is like a 300x improvement!
Ajax jquery asynchronous calls

The primary reason is that UpdatePanel posts back too much data but with jquery ajax calls, you send *only* the data you need to, to the server. Further, UpdatePanels try to recreate the whole control tree (Page) before sending it back in the response but with the jquery ajax thing you are in charge and you just need to hide the current question and show the next one (which would obviously be faster)!

Safari problems with UpdatePanel: As expected, UpdatePanels run even more slow in Safari and as expected (again) jquery ajax calls take about the same time. The below screenshots will help it visualize more clearly

UpdatePanel performance in Safari -
ASP.net UpdatePanel slow performance Ajax for Safari browser


jquery ajax performance in Safari

Ajax jquery asynchronous calls for Safari browser

As you can see, the performance gains in Safari are rather huge!

Problems with URL fragments usage by UpdatePanels and RSH: This is again very important if your website has multiple tools / functionalities that rely on URL fragments. UpdatePanels don't play with any other tool / functionality that uses URL fragments. Yes, since UpdatePanels store their "history" in the URL fragments, if something else is also using URL fragments then ScriptManager's Navigate event (triggered by browser's back button) will not find it's "history". This can be resolved though by putting in some checks to ensure that the current URL fragment is the one to be used by the UpdatePanel. Switching to RSH for all history management resolves this issue perfectly.

Development times comparison: Surprisingly, UpdatePanel ajax implementation doesn't save too much time over the jquery ajax implementation. If jquery were to be absent, then yeah UpdatePanel would generate quite a bit of code for us even for regular asynchronous web service calls. You won't be churning out 500 lines of jquery code for every line of UpdatePanel code! With jquery's ajax method, the amount of code written is pretty much the same (if not less)!

Development technologies comparison: This is one of the key factors. With UpdatePanel you can write the code (saving data, moving to next question etc) in a server side language (C#, VB.NET etc) but with jquery ajax you are stuck with a client side language (javascript / jquery). The server side languages generally have better debugging tools and better built in features to allow better implementation from design, maintenance and coding efficiency point of view. But it can very well be a personal thing.

Verdict: jquery ajax calls with RSH prove to be a better option if speed and versatility (across different browsers and OS etc) is a major concern. UpdatePanels might work better if the technological expertise and macro design details is a more important.

To learn how to use RSH, click - RSH (Really Simple History) for Ajax back button problem

To learn how to use jquery ajax, click - jquery ajax calls to webservices

Monday, December 29, 2008

How to call a web service from jquery passing json data

Ok, so today I was finally able to rewrite all the asynchronous webservice calls with jquery using JSON for passing data from JQuery to Webservice (or is it Web service?) and getting result back from Webservice to jquery. For those who don't know whats going on, here's a little background info - As I noted in my previous posts, RSH (Really Simple History) uses JSON quite a bit and JSON doesn't seem to play well with Microsoft ASP.NET Ajax's (or Ajax.net if you prefer) ScriptManager control and I was using ScriptManager control to access my webservices from javascript (JQuery). Today, I finally figured out the best (or atleast easiest) way of calling webservice methods from jquery and using JSON for passing data (webservice's webmethod's arguments) to the webservice and getting the result back to jquery (result of the webmethod's call, yeah i'm verbose!).

And as you'd expect, it made a hell lot of difference in performance! Now when I compare the approach of using a Webservice via a ScriptManager with this approach of calling the Webmethod directly via jquery, the performance improvement in the webservice calls are ridiculous! This is to be expected though as ASP.NET's Ajax ScriptManager generates a slew of helper client side scripts that totally bog the system down...err..ok not totally but the Webservice calls through ScriptManager do seem to add some kilobytes (can be over 100kb too) of extra code. Obviously, the jquery webservice calls implementation comes with it's own overhead too but I personally think that the jquery's overhead are not really deal breaker if you plan to write some little jquery helper functions yourself for making webservice calls. Besides the little fact that since the direct jquery with json webservice calls thingy doesn't require a ScriptManager, you can do it in any language - asp.net, php, ruby, c, assembly....err not assembly I guess...but you get the picture!

Anyhow, enough of my babbling, lets get on to the good stuff...some sample code to show how to go about calling a webservice from jquery (clientside, javascript whatever) via a ScriptManager (ASP.net ajax) and directly from jquery (again clientside, javascript whatever) using json -

How to call a Webservice from jquery using ScriptManager -



1. Import using System.Web.Script namespace and add ScriptService attribute to your webservice class. For example -


using System.Web.Script;
[ScriptService]
public class OurPotentiallySlowWebService: System.Web.Services.WebService


2. Add WebMethod and ScriptMethod attributes to your web-methods that need to be called from javascript/jquery/clientside/mars....ok not mars. Example -


[WebMethod, ScriptMethod]
public string SaveThisDataComingFromJQuery(string data1, data2)


3. Add the following ScriptManager tag at the top of your form

<asp:ScriptManager runat="server" EnablePageMethods="true" ID="BlahScriptManager"
EnableHistory="true" EnablePartialRendering="true" EnableStateHash="false" OnNavigate="BlahScriptManager_Navigate">
<Services>
<asp:ServiceReference Path="~/OurPotentiallySlowWebService.asmx" />
</Services>
</asp:ScriptManager>

4. Call the SaveThisDataComingFromJQuery method from your javascript -

var finallyIGotResult = OurPotentiallySlowWebService.SaveThisDataComingFromJQuery ("datavalue1", "datavalue2");

Yes, that was it! ASP.NET Ajax ScriptManager has simplified the seemingly complex webservice call to ridiculous levels! But as I said, it came at a great cost of many extra kilobytes that might potentially slow your webpage down giving your visitor to hit back button and find some faster and more response website than yours! But fear not, you can do whatever that faster website did to become faster and stay in the game, read on....

How to call Webservices from jquery and use JSON to pass data back and forth -



(First 2 steps will remain the same as above but I've reproduced them below too just in case you knew the folly of ASP.net's ScriptManager and skipped the above section)

1. Import using System.Web.Script namespace and add ScriptService attribute to your webservice class. For example -

using System.Web.Script;
[ScriptService]
public class OurFastestWebService: System.Web.Services.WebService

2. Add WebMethod and ScriptMethod attributes to your web-methods that need to be called from javascript/jquery/clientside/mars....ok not mars. Example -

[WebMethod, ScriptMethod]
public string SaveThisDataComingFromJQuery(string data1, data2)

3. Here the fun starts, you call the webmethod with the $.ajax method that totally rocks! Example -

$.ajax({
type: "POST",
url: "OurFastestWebService.asmx/SaveThisDataComingFromJQuery",
data: "{'data1':'datavalue1','data2':'datavalue1'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) { var iGotResultAndPageisFaster = msg.d; }
error: function(err) { alert('you don't deserve to write code'); }
});

Holy sh-t! What's that "thing" above! Fear not, the good news is that the bolded part on the right of colons is the only stuff you will change most of the time, still I take this piece of code apart below -

$.ajax({ -> This is the name of the jquery method. The little "{" at the end just means that we are sending the parameters / arguments to $.ajax in JSON format. JSON format is basically - {field1:value1, field2:value2}. JSON is a beauty in itself and I might write about it's advance usage later on but I hope you got the basic idea here.

data -> This is just the list of arguments and their values. Thing to keep in mind is that the the argument names here must match with the argument names used in the WebMethod. As you can see, I've used 'data1' and 'data2' both here and in SaveThisDataComingFromJQuery WebMethod.

Rest of the options are kinda self explanatory and won't change so I won't comment on them and seriously you should just make it work and go hit some clubs or something...but if you are married then you may visit http://docs.jquery.com/Ajax/jQuery.ajax#toptions for a fuller list of options.

Yeah, it was *that* easy! So you see that, even if the ASP.net Ajax ScriptManager does help add some code on our behalf the webservice call easier but the difference is not *that* big even with Ajax. And if you add a helper method then even that little difference is eliminated.

How to write a helper method for making $.Ajax calls to webservice -

function iWannaCallMyFastestWebService(datavalue1, datavalue2)
{
$.ajax({
type: "POST",
url: "OurFastestWebService.asmx/SaveThisDataComingFromJQuery",
data: "{'data1':'datavalue1','data2':'datavalue1'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) { var iGotResultAndPageisFaster = msg.d; }
error: function(err) { alert('you don't deserve to write code'); }
});
}

Now you can call this method everywhere and bingo, you've just eliminated the need (and overhead) of ScriptManager, ASP.net Ajax, Ajax.net, Microsoft, Global Warming, completely.....ok not Global Warming but you got the point. Now let's compare the two method calls -

function iFunWithFastestWebservice()
{
iWannaCallMyFastestWebService("yoyo1", "yoyo2");
OurPotentiallySlowWebService.SaveThisDataComingFromJQuery ("datavalue1", "datavalue2");
}

Holy christ! It looks as if our jquery approach even saves some precious space for web service calls! So, now you the truth! Let the force be on your side, happy coding!

Wednesday, December 24, 2008

Sys.Res is undefined Sys.Net is undefined Sys.Application is undefined error ajax json



So, switching to RSH (Really Simple History) for Ajax history back button management I, all of a sudden, started getting the below errors -


Sys.Res is undefined
/ScriptResource.axd?d=pAszYI1Gb4SpsTh8sMT0W6wF1gtmVrXttUVRBvK-ueW1CPqT8yfJ7elHbLz7SUAEaufrYfuec4EOs8rqAu5Babg0xkVae2w4D2gBh1dvVuE1&t=ffffffffa3435222
Line 2798
[Break on this error] if (typeof(val) !== 'number' || ...dOperation(Sys.Res.enumValueNotInteger);

Sys.Net is undefined
[Break on this error] BlahService.registerClass('BlahService',Sys.Net.WebServiceProxy);

Sys.Application is undefined
[Break on this error] Sys.Application.initialize();

Sys.Net is undefined
[Break on this error] BlahService.registerClass('BlahService',Sys.Net.WebServiceProxy);
jsdebug (line 61)
[Exception... "Component is not available" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: file:///C:/Program%20Files/Mozilla%20Firefox/components/nsSessionStore.js :: sss_saveState :: line 1908" data: no]
[Break on this error] this._writeFile(this._sessionFile, oState.toSource());


As you can see in the screenshot above as well, these errors are getting generated from inside ajax.net stuff and that's pretty much the most horrible source of errors/bugs thing that you can get! What I mean to say is that if the source of the error is some code written by some human, then it can be debugged and fixed but if the error is originating from some place like ScriptResource.axd?d=pAszYI1Gb4SpsTh8sMT0W6wF1gtmVrXttUVRBvK-ueW1CPqT8yfJ7elHbLz7SUAEaufrYfuec4EOs8rqAu5Babg0xkVae2w4D2gBh1dvVuE1&t=ffffffffa3435222 then there's squat you can do to fix it! And even more so when one of the errors seems to say Sys.Application.initialize(); then you know that you are doomed!

Anyhow, after lots of caffeine, anguish and praying finally the Lord Google revealed the answer - Turns out that Microsoft's Ajax.net is not compatible with JSON (JSON being used by RSH - Really Simple History plugin)! Go figure! Some little proof-of-concept showed that yes if I get rid of the ScriptManager control (that ships with Microsoft's Ajax.net) toolkit then all those errors will disappear.

<asp:ScriptManager runat="server" EnablePageMethods="true" ID="BlahScriptManager"
EnableHistory="true" EnablePartialRendering="true" EnableStateHash="false" OnNavigate="
BlahScriptManager_Navigate">
<Services>
<asp:ServiceReference Path="~/DynamicUpdater.asmx" />
</Services>
</asp:ScriptManager>


So we are talking about either getting rid of JSON or getting rid of ScriptManager control (or both for that matter!) as possible solutions. RSH (Really Simple History) unfortunately relies on JSON and all of my asynchronous ajax (web service) calls rely on using ScriptManager with EnablePageMethods set to true (with the webservices referenced in the Services as you can see in the above code). Both RSH and the asynchronous calls (Webservice through the ScriptManager) are integral for the system but since Microsoft ajax.net won't play with JSON, I'm scr-wed. But I guess we are all here to do what we are all here to do and I'll be implementing all the asynchronous webservice calls with regular XMLHttpRequest and I'm guessing that it might even give some little performance boost given Microsoft Ajax's ScriptManager control is rather heavy duty stuff.

Update: Dec 29 2008: I successfully implemented the aforementioned functionality, it turned out to be a much better option than using ScriptManager/ASP.net/Ajax and it didn't require a lot of extra code either. Read more here - Calling Webservices from jquery using JSON

Friday, December 19, 2008

How to implement RSH (Really Simple History) for Ajax History Back Button

UPDATE (Mar 2010): I've been looking for more easy to implement browser history management solutions and I think that YUI is a better candidate than RSH in terms of the ease of implementation. Here is my new post on overview of history management solutions and a sample YUI implementation - Implementing YUI Browser History Manager

How to use RSH Really Simple History - perhaps one of the best solutions to the Ajax history back button problem. For those who don't know about the ajax browser history and back button problem - browser's back button doesn't work for Ajax asynchronous calls because Ajax results in partial rendering of pages and therefore browser history is not recorded/saved for all Ajax asynchronous calls. Why - again because all Ajax calls result in partial web-page rendering and for browser history to work (for browser to know when to save the current state in history), a full page refresh has to happen. Browser's are just built that way and we can't really control the history management right out of the box. Another problem is that browser's don't have any events for back and forward buttons. So even if we use something like URL Fragments to get the browser's back button to work for Ajax applications, still we wouldn't know if the user is going back or forward without any system that knows how to store the browser history in a stack and pop it when user hits browser's back button (specifically for ajax ofcourse).

After looking at Gmail, Facebook and Orkut, I figured that a good Ajax browser history back button solution will use iframes and URL fragments in some way. Yeah, Gmail, Facebook and Orkut have flawless ajax history (back button) management. Yeah, gmail has the most awesome ajax back button solution in place. Kudos google coders and designers! Facebook is also not lagging behind, you can see the URL fragments in Facebook's URL but it doesn't always seem to work properly (some times the page redirects!). Orkut too, is using some solution that relies on URL fragments and possibly iFrames. So looking at the ajax browser history (back button) managements in these social networking sites, I got some idea about what I'm looking for and found this thing called RSH (Really Simple History) that seems like the perfect solution (so far).

RSH (Really Simple History) uses iFrames (and more for that matter!) to maintain the stack of browser's history. RSH (Really Simple History) also uses URL fragments to store the browser history. Why - because remember that for an ajax asynchronous call browser doesn't even "activate" the back button. This URL fragments technique used by RSH (Really Simple History) is a hack to "activate" the back button because remember that the browser's back button works for all URL fragment clicks. So, by updating the URL fragments Really Simple History (or RSH) create a "state" in browser's history. Yeah, Really Simple History is using iFrames to actually store the browser history stack for ajax calls and it's using URL fragments to make the browser's back button work for each of those ajax calls (tricking the browser into thinking that user navigated to some link! Neat RSH trick!).

Ok, enough with the talk, lets get back to how to implement RSH or Really Simple History. (Yes, that's kinda the main point of the blog because very few sites explain how to use or how to implement Really Simple History (RSH). Please remember that the code samples I provide below come from ASP.NET development environment but being Javascript/JQuery (clientside code basically) there's not much difference.

1: Download JQuery and include in your web page (skip if already using them). JQuery can be downloaded from JQuery Download for RSH (Really Simple History) and JQuery version (1.2.6 in the code below) will change as per the latest JQuery version you download.

<script type="text/javascript" src="<%= ResolveUrl("~/js/jquery-1.2.6.min.js") %>"></script>

2: Download RSH (Really Simple History) library from http://code.google.com/p/reallysimplehistory/downloads/list and include the the minified JQuery and JSON files (again the version numbers will change as per your latest RSH and JSON versions download).


<script type="text/javascript" src="<%= ResolveUrl("~/js/json2007.js") %>"></script>

<script type="text/javascript" src="<%= ResolveUrl("~/js/rsh.compressed.js") %>"></script>

(JSON2007.js and JSON2005.js were included in the Really Simple History package so I didn't have to download JSON separately).

3: FTP or Upload blank.html (that is there in RSH package) to your website where you want to use Really Simple History. This is important because Really Simple History uses the blank.html file to store the browser history stack (as an iframe in your main web page).

4: Create a method that handles any changes in history events. Please remember from earlier in this article that browsers don't have any events for back and forward buttons so we can't handle them (the back button navigation specifically). Now, Really Simple History can handle back (and forward) button on your behalf and all you need to do is to provide a function that takes a stored history state (that you store a bit later in this article) and decides what to do. If this doesn't make a lot of sense, hang on and just look at the sample code for that method below. I'll explain it in more detail in a little bit.

function historyChange(newLocation, historyData)
{

ShowOldContent(newLocation, historyData);

// OR to simplify

alert('hey I'm going back to ' + newLocation);

}

5: Execute the dhtmlHistory.initialize and dhtmlHistory.addListener methods to your onload function to initialize Really Simple History and create the appropriate listeners respectively. Sample code follows and please take a look at the comments for more clarification -

window.onload = function() {
//Simply initializes the dhtmlHistory object. No change needed.
dhtmlHistory.initialize();

//Adds a listener for browser's back/forward navigation. Just change "historyChange" to
// your method of choice. Note that "historyChange" comes from step 4 above.
dhtmlHistory.addListener(historyChange);

//This adds a starting point to the whole browser history thingy. Not really optional though.
dhtmlHistory.add('default.aspx','link');

};


Please note that whatever you put in dhtmlHistory.add() function, as the first argument, will show up as a URL fragment in your webpage. So if your webpage is http://www.mywebpage.com/ then it will become http://www.mywebpage.com/#default.aspx if default.aspx was your first argument to dhtmlHistory.add() function.

6: Call dhtmlHistory.add() function wherever you want to store the browser history for ajax calls! For example, in your buttons that do some ajax calls, you can call it in the onclick() method. What the dhtmlHistory.add() function will do is to call your historyChange() method in turn and execute your history management code.

So, the final sample code looks like -

<script type="text/javascript" src="<%= ResolveUrl("~/js/json2007.js") %>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/js/jquery-1.2.6.min.js") %>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/js/rsh.compressed.js") %>"></script>

<script type="text/javascript" language="javascript">
window.onload = function() {
dhtmlHistory.initialize();
dhtmlHistory.addListener(historyChange);
dhtmlHistory.add('default.aspx','link');
};

function historyChange(newLocation, historyData)
{
ShowOldContent(newLocation, historyData);
// OR to simplify
alert('hey I'm going back to ' + newLocation);
}
</script>

Yes! You are done! It's as simple as that!

Sample Implementation: Now let's go over a sample implementation because so far it was all pretty much up in the air and you might not be sure about what to put in historyChange() method and what to pass as arguments in dhtmlHistory.add() method and so on. So, I'll present two sample implementations of RSH (Really Simple History) . One is a a wizard like problem and the other is navigating using links in a fancy ajax way. This is what I had to do myself in various different projects.

How to use RSH (Really Simple History) to implement (anchor tags) navigation - This is a common problem in which the user clicks a link (anchor tag) and the whole page goes back for a second as new page is loaded. This interferes with the user's overall experience and might even drive him away the more impatient ones. No need to say that a seamless link (anchors) navigation can help most e-commerce websites considerably. This was always considered a necessary evil though but with RSH (Really Simple History) has come to our rescue and here I present one easy solution to integrate Ajax with page navigation -

1: Attach dhtmlHistory.Add() to all anchor tags's onclick() event handlers
2: Call $('#').load() in your historyChange() function

And you are done! Yeah, that was it! I'll be writing in more details about it though as I think it's a rather big topic in itself if presented with all the required code etc.

How to use RSH (Really Simple History) to implement Ajax driven wizards - Let's say we have a drop down (select) as step 1 and 2 radio buttons in our body tag -

<h1>Ajax driven Wizard</h1>
<div id="divStep1">
<asp:DropDownList ID="ddlStep1" runat="server">
<asp:ListItem Value="">Please Select</asp:ListItem>
<asp:ListItem Value="itep1">item1</asp:ListItem>
<asp:ListItem Value="itep2">item2</asp:ListItem>
</asp:DropDownList>
</div>

<div id="divStep1">
<asp:RadioButton runat="server" groupName="rbStep2a" ID="rbStep2" />
<asp:RadioButton runat="server" groupName="rbStep2b" ID="rbStep2" />
</div>

We attach the javascript event handlers to above as follows (one of the many ways of attaching event handlers) -

protected void Page_Load(object sender, EventArgs e)
{
ddlStep1.Attributes["onchange"] = "moveNext('step2')";
rbStep2a.Attributes["onclick"] = moveNext('step1')";
}

"moveNext" is just some method here that shows the "next" step of the wizard and and saves the data to database so that you can keep track of the intermediate steps of a wizard in case user leaves in the middle

function moveNext(nextStep)
{
if(nextStep == 'step2')
{
$("#divStep2").show();
$("#divStep1").hide()
}
else if(nextStep == 'step1')
{
$("#divStep1").show();
$("#divStep2").hide()
}
dhtmlHistory.add(nextStep,'WizardStep');
saveToDatabase(nextStep);
}

Yes, the above code will create a cyclic not-so-much-of-a-wizard! Please give special attention to the bolded line. This line actually adds the "next step" to browser history and as soon as it's executed you will see # as a URL Fragment. Yeah, that's RSH at work right there.

Using above as a reference, we can write historyChange method as below. This implementation too just shows the "next" div and looks a lot like moveNext() method above but it can change to do anything as per your requirements.

function historyChange(newLocation, historyData)
{
if(newLocation == 'step2')
{
$("#divStep2").show();
$("#divStep1").hide()
}
else if(newLocation == 'step1')
{
$("#divStep1").show();
$("#divStep2").hide()
}
}

Please note that I haven't use the historyData object at all in the above example because I simply didn't need to store anything else. But if I need to store something then yes, we can put anything we want in the historyData object. So, thats how we can use RSH (Really Simple History) for an Ajax driven wizard that allows the user to use back button to go back to the last question (and saves the data to the database as a bonus) with refreshing the page!

Monday, December 15, 2008

name.replace is not a function - jquery bug

While trying to implement RSH (Really Simple History, check out my how to implement RSH - Really Simple History and solve ajax history back button problem article for details), I got this dreaded "name.replace is not a function" error! It really drove me nuts as many seem to have got it reported it to the jquery team but for whatever reason jquery bugtracker has almost always marked it as resolved or moved to subcategories. That might all be right but the problem is that this error is still there and seems to emerge right from the jquery core file! I mean it's alright that jquery team has found it to be an invalid bug or resolved issue or relating strictly to jquery plugins (instead of jquery core) but when I see "name.replace is not a function" popping up in my webpage I have to do something to fix it, lol! And I can't do squat because on tracing back, I realize that "name.replace is not a function" is originating from the jquery core file!

So what to do? I personally did the following -

1) Do whatever needs to be done and make sure that the desired functionality is still maintained. That is, isolate the error producing code such that your functionality is not impacted by the error.

2a) Either change the browser settings to not show the error if you have less than 10 users who can't really tell a browser from a pumpkin pie.

2b) If you have some user base and most importantly if it's an internet application then do this thing that is both next best and next worst to the above approach! ;) Yeah, trap the silly "name.replace is not a function" error in a try catch block. This is bad because you've just hidden some error beyond redemption but the thing is that if you've done step 1 correctly then it doesn't matter all that much. So I just went ahead and did it. Below are steps to how to do it -

a) Search for name=name.replace in jquery-1.2.6.min.js file (or the not-minified version and your version number replaces 1.2.6 obviously).

b) Ignore the name=name.replace that has ""float";" before "name=name.replace" part. Yeah, there are two of the name=name.replace thingees.

c) add a try block before name and close it with a catch block just before the immediate "if" statement.

So initially it was like this -

opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]

And after our little change, it looks like -

opacity=([^)]*)/)[1])/100)+'':"";}try{name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});}catch(e){}if(set)elem[name]

Bingo! The stupid name.replace has finally decided to be a function now! The error is gone and if you've been struggling to "somehow" make it work before you can hit the clubs tonight then you are free to do so! Yeah, do it before some new yet unknown error pops out!

Browser History Back Button - History/Remote Plugin

This particular solution applies to the cases when we want to stop any visible page refreshes as the user browses through the website. What we are trying to do basically is to load a new page as the user clicks on a link (navigates via a link) without refreshing the browser - That is, loading the part of the new page in our current page via Ajax by partially rendering the new content in the current page. But because of partial rendering of the page (the fact that the page is never refreshed), the back button gets lost. This plugin solves the back button browser history problem for this scenario using URL fragments.

Step 1: Download the latest jquery library from http://jquery.com/and include it in your project as follows -

<script type="text/javascript" src="<%= ResolveUrl("~/js/jquery-1.2.6.min.js") %>"></script>
(Please remember that this is just an example and the method/filenames etc will change depending on the names used in your web-development language / platform and jquery version etc.

Step 2: Download history/remote plugin js files from http://stilbuero.de/jquery/history/ (this is the website of Mr. Klaus Hartl, the gentleman who came up with this solution) and include it in your project as follows -

<script type="text/javascript" src="<%= ResolveUrl("~/js/jquery.history_remote.js") %>"></script>

Step 3: Add a class named "seolink" to all your links (anchor tags) that needs history management. Please note that this class doesn't exist in your css file and doesn't have any display attributes, it's solely for the purpose of history management.

Step 4: Add the below code (jquery script) in the head tag of the webpage (or the master template if you are using asp.net masterpages) -

$(document).ready(function() {
  createSeoLinks($("#navigation a").add("a.seolink"));
  $.ajaxHistory.initialize(function (){$("#main-content").load(location.href " #main-content > *")});
  });

function createSeoLinks(links) {
  links.unbind('click').remote('#main-content', function() {
 window.createSeoLinks($("#main-content a.seolink"));
  });
}

Step 5 (optional): Ensure that all the links (anchor tags) have title attributes properly set

Step 6 (optional): Add the below code to the $(document).ready(function() section -

document.title = convertLinkToTitle(window.location);

If you don't know what Step 6 means, the final code in Step 4 will look like this -

$(document).ready(function() {
  createSeoLinks($("#navigation a").add("a.seolink"));
  $.ajaxHistory.initialize(function (){$("#main-content").load(location.href " #main-content > *")});
  });

function createSeoLinks(links) {
  links.unbind('click').remote('#main-content', function() {
  window.createSeoLinks($("#main-content a.seolink"));
  document.title = convertLinkToTitle(window.location);
  });
}

And you are done! Yes, it was that easy!

Now, let explain a few things in the above code -

1) main-content : Refers to the div that contains the content that you want to load whenever a link is clicked. Remember that only the contents of main-content div will change as the user navigates through the website, so you will need to organize your content so that the static elements are kept out of main-content div. It doesn't matter a hell lot though but this organization is a good idea in general.

2) What is in addressbar - Remember that, since the page i snever refreshed, the only thing in addressbar that will change is the url fragment. This is picked from the title of anchor tags and that's why Step 5 is needed. It's not an essential component of the history management process though and if you leave it out then it will be "#remote" followed by some number - (like #remote25 for 25th anchor tag etc)

3) convertLinkToTitle - Again since the page is never refreshed, the page title never really changes. So, I figured that I should update the page title programmatically using the information in the browser's addressbar. So this is a javascript / jquery function that will take the link (in the browser's addressbar) and figure out what the title should be, you will be writing the code yourself depending on what you want in url fragment (or the url itself) and how to translate it into page titles. The way, I wrote it is below -

function convertLinkToTitle(linkStr)
{
  var title = new String();
  title = String(linkStr);
  title = title.substr(title.indexOf('#', 0) 1);
  title = title.replace(/_/g, ' ');
  return title;
}

So this is how you implement the History/Remote Plugin.....feel free to suggest improvements, ask questions or comment on the code....And click - to read about another (and in my opinion) better Ajax Browser History Back Button solution called RSH (Really Simple History)