0

I have a custom ASP.NET control, a dropdown/treeview, which needs to add Begin(End-)RequestHandlers to prevent scrolling to the top of container during UpdatePanel partial postbacks (as described here). They are added dynamically like so:

Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID, string.Format(@"
                  var xPos, yPos;
                  var prm = Sys.WebForms.PageRequestManager.getInstance();

                  function BeginRequestHandler(sender, args) {{
                    if ($get('{0}') != null) {{
                      // Get X and Y positions of scrollbar before the partial postback
                      xPos = $get('{0}').scrollLeft;
                      yPos = $get('{0}').scrollTop;
                    }}
                 }}

                 function EndRequestHandler(sender, args) {{
                     if ($get('{0}') != null) {{
                       // Set X and Y positions back to the scrollbar
                       // after partial postback
                       $get('{0}').scrollLeft = xPos;
                       $get('{0}').scrollTop = yPos;
                     }}
                 }}

                 prm.add_beginRequest(BeginRequestHandler);
                 prm.add_endRequest(EndRequestHandler);  ", this.ItemsContainer.ClientID), true);

The problem begins when I add more than one instance of the control to the page. Both scripts are rendered and registered BUT in the end only one, the last one on the page, ends up attached to the the containers, ie. wherever there is update in panel X or Y, only the JS for panel Y is executed - twice!

A better option would surely be appending just one pair of Begin/End handlers, which I could perform by, for example, adding a static key for the RegisterStartupScript method. The only problem is that I would need to pass a parameter of the panel for currently updating UpdatePanel.

Any idea how to do this, and combine with the above?

Community
  • 1
  • 1
n0e
  • 309
  • 3
  • 12

2 Answers2

1

This modification automatically restores the scroll position of all panels.

<script type="text/javascript">
    (function () {
        var scrolledDivs = [];
        var prm = Sys.WebForms.PageRequestManager.getInstance();

        prm.add_beginRequest(function (sender, args) {

            //store the scroll positions of all "scrolled" div elements
            //UpdatePanel and Panel both are div elements
            scrolledDivs = [];

            $('div').each(function () {
                var div = $(this);
                if (div.scrollLeft() != 0 || div.scrollTop() != 0) {
                    scrolledDivs.push({
                        element: this,
                        scrollLeft: div.scrollLeft(),
                        scrollTop: div.scrollTop()
                    });
                }
            });
        });

        prm.add_endRequest(function (sender, args) {
            //restore scroll positions
            $.each(scrolledDivs, function (index, value) {
                $(value.element).scrollLeft(value.scrollLeft).scrollTop(value.scrollTop);
            });
        });
    })();
</script>

Note: you need to include JQuery

LostInComputer
  • 15,188
  • 4
  • 41
  • 49
  • this seems to be working fine BUT what is happening (probably unrelated with the code itself) is that after attaching both handlers, the first async postback is fine, and the next one returns 'unknown error'. after attaching debugger the unknown exception is thrown in MicrosoftAjax.debug.js, around the line 4723, in Sys.Net.XMLHttpExecutor -> this._onReadyStateChange [...]. You have a clue what might be happening? I've attached VS to C# code, and no exception where thrown there. – n0e Feb 07 '14 at 12:34
  • OK, it seems that if attach only one of the handlers, either Begin.. or End.., the exception is not thrown. Somehow attaching both results in exception and breaks AJAX functionality. – n0e Feb 07 '14 at 13:05
  • Can you post the error when using another browser? Firefox or chrome – LostInComputer Feb 07 '14 at 13:08
  • It seems that [this](http://forums.asp.net/t/1683474.aspx?ie9+Jscript+unspecified+error+I+am+setting+scrolltop+on+EndRequestHandler+from+AJAX) is my problem. The error is from IE8. – n0e Feb 07 '14 at 13:09
  • Ok. I will add a check if the element still exist when i get the time – LostInComputer Feb 07 '14 at 13:11
  • I wonder if the problem is not somewhere in the fact, that UpdatePanel recreates DOM – n0e Feb 07 '14 at 13:18
  • Good point. i have to get the element's id then check if it still exist – LostInComputer Feb 07 '14 at 13:21
1

Using a bit modified code from LostInComputer the solution looks like this:

            Page.ClientScript.RegisterStartupScript(this.GetType(), "scrollRestorer", @"
                  var scrolledDivs = [];
                  var prm = Sys.WebForms.PageRequestManager.getInstance();

                  function BeginRequestHandler(sender, args) {
                    //store the scroll positions of all 'scrolled' div elements
                    //UpdatePanel and Panel both are div elements
                    scrolledDivs = [];

                    $('div').each(function () {
                        var div = $(this);
                        if (div.scrollLeft() != 0 || div.scrollTop() != 0) {
                            scrolledDivs.push({
                                element: this.id,
                                scrollLeft: div.scrollLeft(),
                                scrollTop: div.scrollTop()
                            });
                        }
                    });
                 }

                 function EndRequestHandler(sender, args) {
                    //restore scroll positions
                    $.each(scrolledDivs, function (index, value) {
                        $('#' + value.element).scrollLeft(value.scrollLeft).scrollTop(value.scrollTop);
                    });
                 }

                 prm.add_beginRequest(BeginRequestHandler);
                 prm.add_endRequest(EndRequestHandler);  ", true);

The item itself cannot be stored in array, only ID should be stored.

n0e
  • 309
  • 3
  • 12