I've got an ASP.NET 2.0 web application that is partly navigated by using DropDownList
controls. When one of them is changed, it causes a postback, which is then redirected to another URL depending on what was chosen in the dropdown.
I've noticed strange behavior when using the browser's Back button after using the dropdowns. The procedure is this:
div
), make a selection. The page redirects to the same URL as the first time, not what it should redirect to based on this other dropdown.I've tried this in both Firefox 10 and IE9 and seen the same thing. I looked at the Net tab in Firebug and saw that in the POST for step 3, the correct control is referenced. But when I debug it, the event handler for the wrong dropdown (the one used in step 1) fires.
The code is pretty simple and straightforward. Example of markup:
<asp:DropDownList runat="server" ID="ddlTest" AutoPostBack="true" />
The dropdowns actually aren't plain <asp:DropDownList ... />
elements; I'm inserting optgroup
elements with an approach similar to this.
Example of C#:
ddlTest.Click += new EventHandler(ddlTest_SelectedIndexChanged);
And in ddlTest_SelectedIndexChanged
:
if (ddlTest.SelectedValue != "")
{
Response.Redirect(MyUtilClass.GetUrl(ddlTest.SelectedValue));
}
What's going on here?
UPDATE 2/6/2012: I've fixed this by checking for the content of Request["__EVENTTARGET"]
in my SelectedIndexChanged
event handlers. I'm still curious why it happens, though. Why is the first event repeated? And why does it only happen when the second postback happens from a control below the first one?
Once you click on the back button the last visited page is shown as it is saved on the client is not sent back/requested again to/from the server, this including the last posted value like the once shown after you select the second DropDownlist right after hitting the back button.
The onload method on IE(for other browsers see:http://dean.edwards.name/weblog/2005/09/busted/) of the first page gets fired when you press the back button on the second so using this we can try to save on the client the postback action before redirecting the page, we save it on a hidden value with JS, then once the user goes back the onload methods evaluates if the hidden has a value and if so then you change the location of the page to itself so the page is requested again and all the posted values are cleared out:
page1.aspx
<script type="text/javascript">
function redir(){
var h=document.getElementById('hdR');
if (h.value=='1'){
h.value='0';
document.location.href='page1.aspx';
}
}
function changeHids(){
var h=document.getElementById('hdR');
h.value='1';
}
</script>
</head>
<body onload="redir();">
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" onchange="changeHids();">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
<asp:ListItem>3</asp:ListItem>
<asp:ListItem>4</asp:ListItem>
</asp:DropDownList>
<br />
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="true" onchange="changeHids();">
<asp:ListItem>5</asp:ListItem>
<asp:ListItem>6</asp:ListItem>
<asp:ListItem>7</asp:ListItem>
<asp:ListItem>8</asp:ListItem>
</asp:DropDownList>
<asp:HiddenField ID="hdR" runat="server"/>
</div>
</form>
</body>
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
Response.Redirect("page2.aspx?ddl=1&val=" & Me.DropDownList1.SelectedValue, True)
End Sub
Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
Response.Redirect("page2.aspx?ddl=2&val=" & Me.DropDownList2.SelectedValue, True)
End Sub
page2.aspx
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Response.Write("ddl:" & Request.QueryString("ddl") & " " & "value:" & Request.QueryString("val"))
End Sub
Firefox - Add Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
Response.AppendHeader("Cache-Control", "no-store");
}
Chrome - Add javascript pageload:
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if (is_chrome) {
document.getElementById("form1").reset();
}
you can use Response.Cache properties to solve this issue, as you are allowing to cache the list in browser memory. from MSDN SetAllowResponseInBrowserHistory
When HttpCacheability is set to NoCache or ServerAndNoCache the Expires HTTP header is by default set to -1; this tells the client not to cache responses in the History folder, so that when you use the back/forward buttons the client requests a new version of the response each time. You can override this behavior by calling the SetAllowResponseInBrowserHistory method with the allow parameter set to true.
in your page load method, you add this line .
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(false);
// or else you can do like this
Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d);
Response.Expires = -1;
Response.CacheControl = "No-cache";
}
so that whenever you pressed back, t will requests a new version of the response each time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With