Introduction
I recently hit a runtime error bug while using ASP.NET callback components.
There is a bug in the Microsoft ASP.NET standard library.
Fixing the bug is rather complicated because you have to change the source code you don't have access to.
I could not find a complete step by step article on how to fix the error, this is why I decided to post the entire code.
Background
When running a page, I would hit an error:
"Microsoft JScript runtime error: '__pendingCallbacks[...].async'
is null or not an object"
The error occurs on this line.
function WebForm_CallbackComplete() {
for (i = 0; i < __pendingCallbacks.length; i++) {
callbackObject = __pendingCallbacks[i];
if (callbackObject && callbackObject.xmlRequest &&
(callbackObject.xmlRequest.readyState == 4)) {
WebForm_ExecuteCallback(callbackObject);
if (!__pendingCallbacks[i].async) {
__synchronousCallBackIndex = -1;
}
__pendingCallbacks[i] = null;
var callbackFrameID = "__CALLBACKFRAME" + i;
var xmlRequestFrame = document.getElementById(callbackFrameID);
if (xmlRequestFrame) {
xmlRequestFrame.parentNode.removeChild(xmlRequestFrame);
}
}
}
}
The Problem
It seems that the error is in the for (i=0;
and is the core of the problem. The i
variable is a global variable and it can get changed within the loop.
The fix is to add a var
keyword to make the variable local.
Looking on the internet, you can find that some people also suggest to move the WebForm_ExecuteCallback
lower in the loop.
The Fix
In order to fix your page, you just have to insert this code in the beginning of your page. I personally put it in the body.
<script type="text/javascript">
var GlvDelayedNextPageNo;
function WebForm_CallbackComplete_SyncFixed() {
the var statement ensure the variable is not global
for (var i = 0; i < __pendingCallbacks.length; i++) {
callbackObject = __pendingCallbacks[i];
if (callbackObject && callbackObject.xmlRequest &&
(callbackObject.xmlRequest.readyState == 4)) {
SyncFixed: line move below // WebForm_ExecuteCallback(callbackObject);
if (!__pendingCallbacks[i].async) {
__synchronousCallBackIndex = -1;
}
__pendingCallbacks[i] = null;
var callbackFrameID = "__CALLBACKFRAME" + i;
var xmlRequestFrame = document.getElementById(callbackFrameID);
if (xmlRequestFrame) {
xmlRequestFrame.parentNode.removeChild(xmlRequestFrame);
}
WebForm_ExecuteCallback(callbackObject);
}
}
}
var OnloadWithoutSyncFixed = window.onload;
window.onload = function Onload(){
if (typeof (WebForm_CallbackComplete) == "function") {
WebForm_CallbackComplete = WebForm_CallbackComplete_SyncFixed;
if (OnloadWithoutSyncFixed!=null) OnloadWithoutSyncFixed();
}
}
</script>
Points of Interest
This was because while overloading the onload
function, you could change the behaviour of the rest of your components.
The right method is to override the onload
but within the new onload
, call the previous one.
This is not rocket science, but also probably not obvious for everyone.