I'm always lost when trying to register a
javascript fragment that must be executed on the client side after the postback.
There are several usable methods in ASP.NET WebForms and I never know which one
to choose.
Page.ClientScript
Page.ClientScript.RegisterStartupScript – registers the startup script.
What does it mean “startup”? It is something that is executed when the browser finishes
page loading, which is guaranteed by the fact that “startup” scripts are
rendered just before closing <form> tag. Almost all elements on the page
are processed by the browser at this point and can be referenced from that “startup”
script.
Page.ClientScript.RegisterClientScriptBlock – registers the script block, so it
is rendered somewhere near after the <form> element opening. This block
is executed before the DOM is fully processed and before any “startup” scripts
are executed. “ClientScript” blocks are good place for javascript functions.
Page
Page.RegisterStartupScript and Page.RegisterClientScriptBlock are marked as obsolete and they do
nothing but Page.ClientScript call. Just ignore them.
ScriptManager
Now what about ScriptManager class? RegisterClientScriptBlock
and RegisterStartupScript are there as well. What is the justification for such
duplication? The only difference, according to the documentation (here and here), is that the scripts are “included every time
that an asynchronous postback occurs”. This formulation is slightly confusing.
Scripts registered by ScriptManager’s methods are rendered by non-asynchronous
postback as well. ClientScript’s methods are never rendered by asynchronous-postbacks.
Script registration
after asynchronous postback
The javascript block is not executed if it is a
part of markup in AJAX response. Browser simply doesn’t process such block. Consider
such silly ASPX:
<asp:Button runat="server" ID="Button1" Text="Do postback" OnClick="Button1_Click" />
<asp:Literal runat="server" ID="Literal1" />
and C# code behind with a script:
protected void
Button1_Click(object sender, EventArgs e)
{
Literal1.Text = "<script>alert('Button1
clicked')</script>";
}
Button1 causes postback (when clicked) and
event handler fills Literal1 with the javascript block. This javascript block
is execeuted and the alert message is shown when browser loads the
(synchronous) postback response.
Let’s move to asynchronous postback:
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
<ContentTemplate>
<asp:Button runat="server"
ID="Button1"
Text="Do AJAX
call" OnClick="Button1_Click" />
<asp:Literal runat="server"
ID="Literal1"
/>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger
ControlID="Button1"
/>
</Triggers>
</asp:UpdatePanel>
Code behind remains unchanged.
No message is shown after the Button1 is
clicked. Body of the response should look something like this:
139|updatePanel|UpdatePanel1|
<input type="submit" name="Button1" value="Do AJAX call" id="Button1" />
<script>alert('Button1 clicked')</script>
|152|hiddenField|__VIEWSTATE|/wEPDwUKLTUxODY2NjI0NQ9kFgICAw9kFgICAw9kFgJmD2QWAgI
DDxYCHgRUZXh0BSk8c2NyaXB0PmFsZXJ0KCdCdXR0b24xIGNsaWNrZWQnKTwvc2NyaXB0PmRk88Fv/gu
MXM8Xq/lT5WC+dG66354=|48|hiddenField|__EVENTVALIDATION|/wEWAgL/oouVBgKM54rGBmox+
1LEg7FJSnLOTrjRf5eL73gK|7|asyncPostBackControlIDs||Button1|0|postBackControlIDs|
||13|updatePanelIDs||tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs|
|UpdatePanel1|2|asyncPostBackTimeout||90|13|formAction||WebForm8.aspx|
Alert script is rendered into markup but it is not executed by
the browser. How is it possible that script registration via ScriptManager
works?
This code behind modification could discover
the secret:
protected void Button1_Click(object sender, EventArgs e)
protected void Button1_Click(object sender, EventArgs e)
{
ScriptManager.RegisterStartupScript(this, this.GetType(),
"script", "<script>alert('Button1
clicked')</script>", false);
}
The alert message box is shown this time. Here
is the response:
98|updatePanel|UpdatePanel1|
<input id="Button1" name="Button1" type="submit" value="Do AJAX call" />
|52|hiddenField|__VIEWSTATE|/wEPDwUKLTUxODY2NjI0NWRkwPvseEH2ojph8EJh0MFS5L+TksA
=|48|hiddenField|__EVENTVALIDATION|/wEWAgKaoIz3DwKM54rGBr7RMEQMtuoxxWPUsRRwWxmrCH
/Z|7|asyncPostBackControlIDs||Button1|0|postBackControlIDs|||13|updatePanelIDs||t
UpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncP
ostBackTimeout||90|13|formAction||WebForm8.aspx|45|scriptStartupBlock|
ScriptContentWithTags|{"text":"alert(\u0027Button1 clicked\u0027)"}|
There are two significant changes in the
response: the script is not rendered (unsurprisingly) in the Literal control and there
is something more in the response: scriptStartupBlock.
ASP.NET AJAX library ensures that script
from this “section” is executed after receiving the response. ScriptManager.RegisterClientScriptBlock
is very similar but it uses scriptBlock
“section”.
It is quite easy to navigate through the labyrinth
when it is clear how things work under the hood.