I have a listbox inside an update panel. When I scroll down and select an item, it scrolls back to the top of the listbox. I heard that the dom does not keep track of the scroll position on a postback. Does anyone have a solution/example on how to solve this?
Thanks,
XaiSoft
You're running into this problem because the UpdatePanel
completely replaces your scrolled <select>
element with a new one when the asynchronous request comes back.
Possible solutions:
Use JavaScript to store the scrollTop
property of the <select>
element in a hidden form element before the UpdatePanel
is submitted (by calling the ClientScriptManager.RegisterOnSubmitStatement
method) and then setting it on the new <select>
when the AJAX call comes back. This will be tedious, error-prone, and probably not very compatible (see here).
Use JavaScript to store the <select>
's selectedIndex
property and re-select that item when the AJAX call comes back. Obviously this won't work if the user hasn't selected anything yet.
Don't use UpdatePanel
s. Try jQuery + ASP.NET page methods instead.
var xPos, yPos;
var prm = Sys.WebForms.PageRequestManager.getInstance();
function BeginRequestHandler(sender, args) {
if (($get('Panel1')) != null) {
xPos = $get('Panel1').scrollLeft;
yPos = $get('Panel1').scrollTop;
}
}
function EndRequestHandler(sender, args) {
if (($get('Panel1')) != null) {
$get('Panel1').scrollLeft = xPos;
$get('Panel1').scrollTop = yPos;
}
}
prm.add_beginRequest(BeginRequestHandler);
prm.add_endRequest(EndRequestHandler);
//Note: "Panel1" Panel or div u want to maintain scroll position
//Note: This Java Script should be added after Scriptmanager*****
//Maintain Scroll Position for Panel/Div with out Update panel
window.onload = function() {
var strCook = document.cookie;
if (strCook.indexOf("!~") != 0) {
var intS = strCook.indexOf("!~");
var intE = strCook.indexOf("~!");
var strPos = strCook.substring(intS + 2, intE);
document.getElementById('Panel1').scrollTop = strPos;
}
}
function SetDivPosition() {
var intY = document.getElementById('Panel1').scrollTop;
document.title = intY;
document.cookie = "yPos=!~" + intY + "~!";
}
//Note: "Panel1" Panel id or div id for which u want to maintain scroll position
It seems that the following code example scrolls in the following way:
Internet Explorer 8: After postback the selected item is the first visible item.
Firefox: After postback the selected item is always visible (but might be the last visible item).
Chrome: After postback, the selected item might be hidden since the listbox scrolls to the top, as you say.
<asp:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<asp:ListBox ID="lb1" runat="server" Height="100px" AutoPostBack="true">
<asp:ListItem>A</asp:ListItem>
<asp:ListItem>B</asp:ListItem>
<asp:ListItem>C</asp:ListItem>
<asp:ListItem>D</asp:ListItem>
<asp:ListItem>E</asp:ListItem>
<asp:ListItem>F</asp:ListItem>
<asp:ListItem>G</asp:ListItem>
<asp:ListItem>H</asp:ListItem>
</asp:ListBox>
</ContentTemplate>
</asp:UpdatePanel>
You can still achieve the partial postback using the UpdatePanel
containing a ListBox
, but prevent it from being overwritten by a new instance by setting the following on the UpdatePanel
:
ChildrenAsTriggers="False"
This as stated in the MSDN:
Gets or sets a value that indicates whether postbacks from immediate
child controls of an UpdatePanel control update the panel's content.
Set the ChildrenAsTriggers property to false if do NOT you want
postbacks from immediate child controls of the UpdatePanel control to
cause an update of the panel's content.
The one caveat to this is if you are trying to do any other visual manipulation to the ListBox from the server-side (i.e. adding CSS
attributes to the items on postbacks), then you will not see them render until another unrelated postback occurs. If all you are doing is making selections than setting ChildrenAsTriggers="False"
will work.
For the enterprise application I was working on, it turned out that the MasterPage.Master page was handling the Sys.WebForms.PageRequestManager.getInstance().add_endRequest event and setting window.scroll(0,0) within it. The content pages were obviously executing the window.scroll(0,0) on each trigger of the contentpage's UpdatePanel. I tried overriding the add_endRequest functionality in the content page but could not get that to work. Eventually I just modified the Master.Master to not do window.scroll(0,0).