jueves, 15 de mayo de 2014

Conservar la posición del scroll de página tras un Postback

Recientemente he tenido que montar un formulario web en ASP.NET cuya extensión vertical  se me ha ido un poco de madre. Cuando estuve probándolo me di cuenta de que al hacer los postback el scroll me devolvía al principio de la página. Esto obviamente es un engorro para el usuario, que en páginas un poco densas -por ejemplo rellenando datos en un formulario grande- puede llegar a verse un poco desorientado. Además el efecto queda feo y resta navegabilidad. Como de costumbre es algo que probablemente voy a necesitar más adelante, así que tras dar con la solución -Google gratia- lo dejo aquí referido.


A partir de ASP.NET 2.0 -que es con lo que yo trabajo- la solución viene de la mano de la propiedad "maintainScrollPositionOnPostBack". Tenemos tres formas de usar esta propiedad:

En archivo web.config
Podemos ubicar esta propiedad en el web.config de la aplicación, de esta manera todas las páginas del proyecto mantendrán la posición del scroll después de un postback:

<system.web>
   <pages maintainScrollPositionOnPostBack="true">
   ...
   </pages>
</system.web>

En directiva de página
Se puede agregar como propiedad del objeto Page en la directiva de página, al principio del fichero .aspx:

<%@ Page Language="vb" maintainScrollPositionOnPostBack="true" %>

En método Page_Load
Podemos invocar esta propiedad en el método Page_Load de la página:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
   ...
   Me.MaintainScrollPositionOnPostBack = true
   ...
End Sub

Hay que tener en cuenta que la clase que define nuestra página debe heredar de System.Web.UI.Page.

ACTUALIZACIÓN
Después de varias pruebas y de leer un poco más sobre el asunto de los scrolls, he llegado a la conclusión de que la propiedad "maintainScrollPositionOnPostBack" tampoco es la panacea... No funciona siempre, ni en todos los navegadores, y me temo que no se lleva bien con determinados elementos clásicos de la maquetación (aunque pasados de moda) como los frames. También presenta problemas con los RequiredFieldValidator y los ValidationSummary (y yo tengo de todo eso en mis páginas...). Pero oye, si a alguno de los que llega hasta este blog en busca de ayuda le funciona... ¡Cojonudo! Para mi, lo de cascar la propiedad en el web.config y olvidarme era demasiado bonito para ser verdad, y al final he optado por solucionar la papeleta con JavaScript.

Hay soluciones propuestas para todos los gustos, aunque la mayoría giran en torno a lo mismo: guardar las coordenadas de nuestra posición en la página para usarlas después de un PostBack, y tener la ilusión de que no nos hemos movido del sitio... En mi caso sólo necesito el scroll vertical, así que sólo guardaré mi posición en el eje de la Y. En el formulario web voy a meter un nuevo input oculto llamado "scroll" que será el encargado de almacenar mi posición.

<input type="hidden" id="scroll" runat="server" />

Luego hay que implementar dos pequeñas funciones JavaScript que van a ser las encargadas de obtener esa posición y de restablecerla después de un PostBack.

<script type="text/javascript">

function getVScroll() {
   document.getElementById('scroll').value = document.getElementById('DivAreaTrabajo').scrollTop; 
}

function setVScroll() {  
   document.getElementById('DivAreaTrabajo').scrollTop = document.getElementById('scroll').value;
}  

</script>

La función getVScroll obtiene el scroll vertical actual en DivAreaTrabajo (que en la práctica agrupa toda la zona funcional de trabajo... al menos en mis páginas). Este valor se almacena en el elemento "scroll" del FORM. Esta función tiene que ser invocada en la propiedad "onScroll" del DIV, lo que dará lugar a que se guarde la posición cada vez que haya un scroll dentro de ese elemento.

La función setVScroll restablece el valor almacenado en el input "scroll" a través de la función scrollTop del DIV. SetVScroll tiene que llamarse en la propiedad onLoad del BODY, lo que desplazará el scroll a la posición almacenada cada vez que se recargue la página después de hacer PostBack.

6 comentarios:

  1. Que tal amigo, estoy implementando tu solución pero me he dado cuenta que cuando recarga la pagina se pierde el valor de input, este regresa a cero y no permite asignar el valor de la nueva posición guardada.

    ResponderEliminar
  2. Sin ver tu código es difícil saber que te está pasando. La respuesta convencional es que compruebes que estás llamando correctamente a las funciones y estés ejecutando correctamente el código JavaScript. ¿A qué te refieres con "recargar" la página? porque si estás pulsando F5 no estás haciendo un "postback", haces un GET y te cargas cualquier cosa que hayas intentado guardar en el imput oculto del webform...

    ResponderEliminar
  3. hola, que tal lleve a cabo dos ejemplos smartnavigation y
    tu ejemplo maintainScrollPositionOnPostBack="true y me dá directamente un error

    ResponderEliminar
    Respuestas
    1. Buenas Daniel. Si revisas la "ACTUALIZACIÓN" del artículo verás que finalmente no resolví el problema con la propiedad "maintainScrollPositionOnPostBack" porque me daba problemas. Como puedes leer, en su lugar usé un poco de JavaScript.

      Eliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. Hola, el ejemplo de javascript anda perfecto, en movil no lo hace correctamente, habra que ajustar algo en el codigo?

    ResponderEliminar