views:

1888

answers:

5

Im working on a project in MVC and have enjoyed learning about it. There are a few growing pains but once you figure them out it's not bad. One thing that is really simple in the WebForms world is maintaining the scroll position on a page. All you do is set the MaintainScrollPositionOnPostback property to true. However, in MVC, Im not using postbacks so this will not work for me. What is the standard way of handling this?

Edit: Ajax is acceptable, but I was also wondering how you would do it without AJAX.

A: 

My own workaround is using some info in the ViewData to know what area must be shown in the backnavigation, and a little javascript to position the page's cursor:

In the View, an element like this:

<h3 id="tasks">
    Contained tasks
</h3>

And the javascript to repositionate the page:

<script type="text/javascript">
    addOnLoad(goAnchor);

    function goAnchor() {
        var paging = <%= //Here you determine (from the ViewData or whatever) if you have to position the element %>;
        if (paging == "True") {
            window.location.hash = "tasks";
        }
</script>

You could use a switch to determine what element from the view page you must relocate.

Hope it helps.

mapache
This doesn't keep the exact location like Web Forms did.
Nick Berardi
+5  A: 

Actually there is no standard way of handling this, this was a Microsoft hack to support their post back model. They needed this because every control did a post back and the user would constantly be pushed back to the top of the page.

The recommendation for use with MVC is to do most of your post back to servers using AJAX. So that the page doesn't have to rerender the the focus is not moved. jQuery makes AJAX really easy, and there is even default forms like

<% Ajax.BeginForm(...) %>

Which will take care of the AJAX side of things for you.

Nick Berardi
A: 

a very not-nice way to do this is using cookies.

If you use ONE page in your MVC which handles the other pages you could a code-snippet to it that loads every page which creates a cookie (if non-existent) called "scrolltop". There are ways to have javascript automatically update this cookie when the user scrolls up or down by catching these events or watching the scrollTop value.

On a new page you just have to load the saved position and make the view scroll there in 0 milliseconds (with Mootools or any Ajax script this should be possible) and the user will be exactly where they were.

I don't know much about asp so I don't know if a method exists to anchor to a current y-position. Javascript is a fast and easy way. Anchors in HTMl could be an option if you had every element anchored and posted the anchor to other pages.

xaddict
+3  A: 

The way MaintainScrollPositionOnPostback works is that it has a pair of hidden fields: __SCROLLPOSITIONX and __SCROLLPOSITIONY

On a postback, it sets these,

function WebForm_GetScrollY() {
if (__nonMSDOMBrowser) {
    return window.pageYOffset;
}
else {
    if (document.documentElement && document.documentElement.scrollTop) {
        return document.documentElement.scrollTop;
    }
    else if (document.body) {
        return document.body.scrollTop;
    }
}
return 0;
}
function WebForm_SaveScrollPositionSubmit() {
    if (__nonMSDOMBrowser) {
        theForm.elements['__SCROLLPOSITIONY'].value = window.pageYOffset;
        theForm.elements['__SCROLLPOSITIONX'].value = window.pageXOffset;
    }
    else {
        theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX();
        theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY();
    }
    if ((typeof(this.oldSubmit) != "undefined") && (this.oldSubmit != null)) {
        return this.oldSubmit();
    }
    return true;
    }

and then it calls RestoreScrollPosition:

function WebForm_RestoreScrollPosition() {
    if (__nonMSDOMBrowser) {
        window.scrollTo(theForm.elements['__SCROLLPOSITIONX'].value, theForm.elements['__SCROLLPOSITIONY'].value);
    }
    else {
        window.scrollTo(theForm.__SCROLLPOSITIONX.value, theForm.__SCROLLPOSITIONY.value);
    }
    if ((typeof(theForm.oldOnLoad) != "undefined") && (theForm.oldOnLoad != null)) {
        return theForm.oldOnLoad();
    }
    return true;
}

But as most people said, MVC should be avoiding postbacks anyway.

Richard Gadsden
Humph! Can't work out how to edit this to put in a code sample nicely - anyone want to tell me how I'm being stupid?
Richard Gadsden
A: 
<%
   if(!ViewData.ModelState.IsValid)
   {
%>
   window.location.hash = 'Error';
<%
   }
%>

 <a name="Error"></a>