Fix JavaScript Error in Web Forms Spot the Culprit

Hi, I’m the developer who had to chase down this bug for our latest Web Forms project. Below is the exact path I took from seeing the red error line in IE to pushing a cleaner, user-friendly page into production. I’m sharing every step so the next person (maybe future-me) can fix it in minutes instead of hours.

Error Show:

<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['ctl01'];
if (!theForm) {
    theForm = document.ctl01;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
//]]>
</script>

Asp.Net/HTML:

    <asp:ScriptManager ID="manager" runat="server" ></asp:ScriptManager>
    <asp:UpdatePanel ID="platformOutputTypes" runat="server" UpdateMode="Always" >
        <ContentTemplate >
            <p>
                <label>Platform</label>
                <asp:DropDownList ID="platform" AutoPostBack="true" runat="server" onselectedindexchanged="PlatformSelectedIndexChanged" ></asp:DropDownList>
            </p>

            <asp:CheckBoxList TextAlign="Left" ID="reportOutputTypes" runat="server" />
        </ContentTemplate>
   </asp:UpdatePanel>

I’m also using jQuery on the page.

The Code That Explode

I started with a bare bones test page so I could reproduce the problem without the noise of our full master page. Paste this into a brand-new Web Forms site and pick a value in the drop-down you’ll slam straight into theForm.submit();.

<%@ Page Language="C#" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>UpdatePanel test</title>
</head>
<body>
<form id="ctl01" runat="server">
<asp:ScriptManager ID="manager" runat="server" />
<asp:UpdatePanel ID="platformOutputTypes" runat="server" UpdateMode="Always">
<ContentTemplate>
<p>
<label>Platform </label>
<asp:DropDownList
ID="platform"
AutoPostBack="true"
OnSelectedIndexChanged="PlatformSelectedIndexChanged"
runat="server">
</asp:DropDownList>
</p>

<asp:CheckBoxList ID="reportOutputTypes" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>

And here’s the little script ASP.NET pushes into the page submit() is where IE trips:

<script type="text/javascript">
var theForm = document.forms['ctl01'];
if (!theForm) { theForm = document.ctl01; }
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit(); <!-- boom -->
}
}
</script>

Why IE Screams “Member not found”

  • Straight fact: theForm is the real <form>.
  • JavaScript expects theForm.submit to be a function.
  • Ancient IE has a quirk any control called submit inside that form hides the real function.
  • So when the script calls submit(), IE finds an <input> element instead of the built-in method and raises Member not found.

Sneaky Ways The Name Slips in

CulpritWhat it looks like in HTML
A later button<input type="button" id="submit" …>
A jQuery plug-in<input type="hidden" name="submit" …>
A poorly-named server control<asp:Button ID="submit" …>

My Quick Rescue Checklist

  1. View the generated HTML (F12 ➜ Elements ➜ search submit).
  2. Rename every id/name that collides—submitbtnSubmit, resetbtnReset, etc.
  3. Re-load, smile, zero errors.

Tip: In ASP.NET 4+ set ClientIDMode="Static" and take full control of client IDs.

The Cleaned Up

I rewired the markup so no control shadows a form method and split the logic into tidy pieces.

<asp:ScriptManager runat="server" />

<asp:UpdatePanel ID="upMain" runat="server" UpdateMode="Conditional">
<ContentTemplate>

<!-- platform selector -->
<asp:DropDownList
ID="ddlPlatform"
runat="server"
AutoPostBack="true"
OnSelectedIndexChanged="PlatformChanged">
</asp:DropDownList>

<!-- a real button, safely named -->
<asp:Button ID="btnGo" runat="server"
Text="Refresh" CssClass="btn"
OnClick="BtnGo_Click" />

<!-- outputs that depend on the platform -->
<asp:CheckBoxList ID="cblOutputs" runat="server" />

</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddlPlatform"
EventName="SelectedIndexChanged" />
<asp:AsyncPostBackTrigger ControlID="btnGo"
EventName="Click" />
</Triggers>
</asp:UpdatePanel>

Code-behind (C#):

Protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ddlPlatform.DataSource = GetPlatforms();
ddlPlatform.DataBind();
}
}

protected void PlatformChanged(object sender, EventArgs e) => ReloadOutputs();
protected void BtnGo_Click(object sender, EventArgs e) => ReloadOutputs();

private void ReloadOutputs()
{
cblOutputs.DataSource = GetOutputs(ddlPlatform.SelectedValue);
cblOutputs.DataBind();
}

Result: the page posts back smoothly, no JavaScript crash, and our QA team finally closed the ticket.

Little UX Booster

All front-end only drop each snippet in Site.js and register it with ScriptManager.

Loading Spinner During async

Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(() => $('#spinner').show());
Sys.WebForms.PageRequestManager.getInstance().add_endRequest (() => $('#spinner').hide());
<div id="spinner" style="display:none">Loading…</div>

Remember The Last Chosen Platform

$(function () {
const key = 'lastPlatform';
const $ddl = $('#<%= ddlPlatform.ClientID %>');

$ddl.val(localStorage.getItem(key) || $ddl.val());
$ddl.change(() => localStorage.setItem(key, $ddl.val()));
});

Instant Client Side Filter for The Check Box List

$(function () {
const $list = $('#<%= cblOutputs.ClientID %>');
const $search = $('<input type="text" placeholder="Filter…">').insertBefore($list);

$search.on('input', function () {
const q = this.value.toLowerCase();
$list.find('input[type=checkbox]').each(function () {
const $item = $(this).parent();
$item.toggle($item.text().toLowerCase().includes(q));
});
});
});

Final Thought

That’s the one-line lesson this bug hammered into my brain. The fix was nothing more than a rename, yet it burned a chunk of my afternoon because I chased the Update Panel, jQuery, even the network tab before I opened the raw HTML.

Related blog posts