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 simpl
I used name attributes in tags. No javascript used.
The page that I wanted to return to had <a> tags with name attribute, e.g. <a name="testname">.
The page (view) I returned from used tag <a href="<%: Request.UrlReferrer %>#testname">Back</a>". Request.UrlReferrer is used to go to previous page. #testname scrolls the page position to tag with name "testname".
<%
if(!ViewData.ModelState.IsValid)
{
%>
window.location.hash = 'Error';
<%
}
%>
<a name="Error"></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.
10 years on and a different JS solution. The other JS solution waits for the page to scroll and when the page loads scrolls to whatever position was saved. That's fine for probably most folks (although it doesn't remove the value so the page would always scroll to that position when you reviewed that page...). My solution is to wait for the form to submit:
(Yes, it is using jQuery, but the site has a lot of it...)
// OWNER'S FORM POSITION
if ($("[js-owner-request]").length) {
$("[js-owner-request]").on("submit", function() {
localStorage['owner-request__scrollTop'] = $(this).offset().top;
});
if (localStorage['owner-request__scrollTop'] !== "null") {
$(document).scrollTop(localStorage['owner-request__scrollTop']);
localStorage['owner-request__scrollTop'] = "null"; // set to null so we don't always scroll...
}
}
This scrolls back to the top of the form, that way any error messages would be visible as you might have scrolled beyond the validation summary.
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.
Here's a simple, pure Javascript solution which I've tested in FF4 and IE9 only.
The idea is that this solution should degrade gracefully by falling back to the standard #anchor
tags on a page. What I'm doing is replacing those #anchor
tags on the fly with the X and Y coordinates, then on load, I simply read those values from the querystring and scroll there. If this fails for some reason, the browser should still navigate to the #anchor
position...
Markup:
<a href="/somecontroller/someaction/#someanchor">My Link</a>
jQuery:
$(function() {
// RESTORE SCROLL POSITION
RestoreScrollPosition();
// SAVE SCROLL POSITION
$('a:not(a[href^="http"])').filter('[href$="#someanchor"]').each(function() {
$(this).click(function() {
var href = $(this).attr('href').replace("#someanchor","");
if (href.indexOf('?') == -1) {
href = href + '?x='
} else {
href = href + '&x='
}
href = href + window.pageXOffset;
href = href + '&y=' + window.pageYOffset;
$(this).attr('href', href);
});
});
}
A couple of helper methods:
function RestoreScrollPosition() {
var scrollX = gup('x');
var scrollY = gup('y');
if (scrollX != null && scrollY != null) {
window.scrollTo(scrollX, scrollY);
return true;
}
return false;
}
function gup(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);
if (results == null)
return "";
else
return results[1];
}
This fits my needs, but could be more generic/reusable - I'd be happy for someone to improve on this... :-)