ScrollSpy con Materialize

En este artículo vamos a empezar con algo sencillo, para ver como integrar materialize en Angular y empezar a familiarizarnos con las posibilidades que se abren ante nosotros.

Vamos a hacer lo que se conoce como ScrollSpy. Consiste en tener todo nuestro contenido en distintas secciones, una debajo de otra, en la misma vista. Además, tendremos una barra de navegación fija, ya sea horizontal o vertical. Al pulsar sobre cada uno de los enlaces, el contenido se desplazará, arriba o abajo, para situar la sección correspondiente en el el viewport. Sin embargo, no queremos que ese desplazamiento sea un salto brusco, al estilo de bootstrap. Es eficiente, pero tosco y agresivo. En su lugar, el desplazamiento se producirá de forma suave, de forma que el usuario pueda apreciar el deslizamiento. Esto mejor la experiencia de vistia de nuestro sitio, y lo hace mucho más agradable.

Como complemento, cuando pulsemos un enlace de la barra de navegación, este quedará resaltado, para que el usuario vea claramente en que sección de la vista se encuentra. Así mismo, si desplazamos el contenido con las teclas, o con la barra de scroll de la página, o la rueda del ratón, según se vayan mostrando las distintas secciones en el viewport se activará el correspondiente enlace. El efecto es exteremadamente simple de programar, pero de un gran impacto visual.

INSTALANDO MATERIALIZE

Para este artículo, y para los sucesivos, el primer paso es, por supuesto, integrar materialize con nuestro proyecto Angular. A este respecto, cuando buscas información en Internet, la situación puede volverse confusa rápidamente. Muchas páginas te hablan de integrar materialice con Angular 4, Angular 2 e, incluso, Angular JS. Aunque de Angular 2 a Angular 6 algunas cosas han cambiado poco, otras han mejorado o se han simplificado sustancialmente. El resultado, es que muchos resultados que encuentras están obsoletos, y las cosas no funcionan como esperas. Aquí vamos a trabajar con Angular 6 (la versión más actual en el momento de redactar este artículo, en septiembre de 2018).

Lo primero que vamos a hacer, claro, es crear un nuevo proyecto:

ng new ang6-scrollspy -p a6ss --routing=true

A continuación, y una vez creado el proyecto, instalamos (como no puede ya ser de otro modo) jQuery en primer lugar, y materialize a continuación. Para ello, en la consola de mandatos de VSC, en la raíz del proyecto, tecleamos:

npm install jquery --save
npm install materialize-css@next

El siguiente paso es, como siempre, establecer las referencias necesarias a las hojas de estilos y scripts necesarios en angular.json:

Material Design nos ofrece una gran batería de iconos, en formato SVG, que podemos usar en nuestra aplicación. En este caso sólo vamos a necesitar uno pero, referenciando correctamente la librería de Material Design, tendremos disponibles todos los que podamos llegar a necesitar. Esta llamada la incluimos en el archivo index.html de nuestra aplicación, así:

En este mismo artículo veremos como usar los iconos de Material Design. De momento, con la línea que ves resaltada ya los tenemos disponibles en la aplicación. Puedes ver la colección completa de iconos que tienes disponibles en https://material.io/tools/icons/?style=baseline.

Con esto ya tenemos nuestro proyecto listo para usar materialize. Los pasos que hemos visto en el apartado anterior serán siempre comunes a cualquier proyecto en el que deseemos integrar este framework css.

LAS SECCIONES DE NUESTRA SPA

Vamos a construir las secciones de contenidos de nuestra página. Estas serán distintas vistas que luego irán colocadas una debajo de otra en la vista principal de la página. De este modo, tendremos un contenido por el que desplazarnos. Una barra de navegación, con enlaces a cada una de las secciones, permitirá desencadenar los scrolings.

Aunque las secciones podríamos crearlas en distintos módulos, si nos conviniese por razones organizativas, en este ejemplo las vamos a crear todas (hasta un total de cinco) en un sólo módulo al que llamaremos sections, que crearemos así:

ng g m sections

Y, dentro de este módulo crearemos cinco componentes, cada uno de los cuales contendrá una sección de lo que luego será la vista principal, así:

ng g c sections/Section01 --export
ng g c sections/Section02 --export
ng g c sections/Section03 --export
ng g c sections/Section04 --export
ng g c sections/Section05 --export

En cada una de estas secciones meteremos los contenidos deseados. Como el objetivo en este artículo es conocer el funcionamiento de los scrolling con materialize, sólo he puesto, como contenidos, un rótulo y una imagen en cada sección. Es, como si dijéramos, la versión gráfica del Lorem Ipsum. Además, le hemos dado a cada sección unos estilos muy sencillos en el coresspondiente archivo .css de cada componente.

LA BARRA DE NAVEGACIÓN

Este es un elemento al que debemos prestar cierta atención, máxime siendo este el primer trabajo que realizamos con materialize. Si bien el funcionamiento de las barras de navegación es, conceptualmente, el mismo que cuando las creamos empleando bootstrap, si hay algunas diferencias en cuanto a estilos y algunas prestaciones, que debemos conocer. Lo que podemos necesitar saber sobre barras de navegación en materialice lo encontraremos en https://materializecss.com/navbar.html. Te sugiero que leas la documentación que allí aparece. Aquí vamos a conocer los detalles específicos de la barra de navegación de nuestro proyecto.

En primer lugar, fíjate que la forma de crearla es, básicamente, la misma que siempre: una etiqueta envolvente (que puede ser nav, como en este caso o, incluso, en programación más artesanal, un simple div) y, dentro una lista de tipo ul con los enlaces en los elementos de la misma. Observa que aquí los enlaces tienen el atributo href, en lugar del atributo routerLink habitual en aplicaciones Angular. Esto no tiene nada que ver con el hecho de usar materialice, sino con que estos enlaces direccionan a distintos puntos de una misma vista, como veremos cuando terminemos de construir la estructura. Es decir, no son enlaces que apunten a otra vista o que carguen otro componente, sino que son lo que, tradicionalmente, se ha conocido siempre como enlaces internos. En estas circunstancias, los enlaces se contruyen con su atributo nativo de HTML.

Observa que fuera de la envolvente hay lo que parece ser una copia de la lista de enlaces, con la clase sidenav. Esta clase es propia de materialice, y permite crear la barra de navegación lateral en dispositivos móviles, al estilo de las aplicaciones de Google. Es decir, cuando nuestra aplicación se esté ejecutando en un equipo de escritorio, el menú aparece en la barra de navegación horizontal de la parte superior. Cuando se esté ejecutando en un dispositivo móvil u otro con reolución más reducida, la barra de navegación aparece y desaparece en formato vertical, en la parte izquierda de la pantalla. En el primer caso, los enlaces que funcionan son los que hay en la primera lista, la que se encuentra en la envolvente nav. En el caso de dispositivos móviles, los enlaces que funcionan son los que hay en la segunda lista, la que tiene la clase sidenav. Puede que estés pensando que esto es engorroso, si tienes que duplicar la lista de enlaces. Sin embargo, en cuanto lo pienses, verás que es una solución muy inteligente aportada por materialice. Esto nos permite que, en cualquier proyecto, las opciones disponibles para dispositivos móviles no tengan que ser, necesariamente, las mismas que las de un equipo de escritorio. Es normal, teniendo en cuenta que cada equipo tiene características propias y puede haber componentes cuyas vistas necesiten espacio, y resulte imposible acomodarlas en pantallas pequeñas. En ese caso, estas opciones no aparecerían en el menú de dispositivos móviles. O, si integras tu aplicación mediante Ionic (por ejemplo) para crear una webapp, en el ordenador de escritorio no contarás con dispositivos como GPS o acelerómetro, lo que puede hacer que ciertas opciones sean inadecuadas para ordenadores convencionales. Por esta razón, tener la posibilidad de crear menús diferentes es, sencillamente, genial.

En la barra de navegación vemos también otro elemento interesante. Es la siguiente línea:

<a href="#" data-target="mobile-demo" class="sidenav-trigger"><i class="material-icons">menu</i></a>

Esta es la que, cuando se reduce el ancho de la pantalla, crea el típico menú de hamburguesa, que nos permite desplegar la lista lateral izquierda de la que hablábamos hace un momento. Observa que crea una etiqueta i con la clase material-icons. Dado que tenemos los iconos de Material Design importados en el index.html, como veíamos al principio de este artículo, la palabra menu que aparece en el código no se muestra tal cual, como una cadena literal, si no que muestra el icono con ese nombre, de todo el juego de iconos disponible.

Aún hay algo más. Para que al pulsar ese icono se active correctamente la barra lateral de menús, en el controlador de NavbarComponent (navbar.component.ts), debemos añadir las siguiente líneas:

Por lo demás, la barra de navegación la rematamos retocando algunos estilos en navbar.component.css, según nuestras preferencias o necesidades.

INTEGRANDO TODO

Ya tenemos creados los componentes con las secciones que tendrá nuestra página, en los componentes del módulo sections. En el HTML de cada uno hay una envolvente general (un div) con un atributo id, que le asigna un identificador a cada contenedor. Estos identificadores coinciden con los atributos href de los enlaces. También tenemos nuestra barra de navegación en un componente llamado NavbarComponent que hemos ubicado en un módulo llamado globals.

Todo esto lo vamos a integrar en el AppComponent. Lo primero, naturalmente, es importar, en app.module.ts los módulos GlobalModule y SectionsModule. Esto ya lo sabemos. Si queremos usar los componentes de un módulo en otro, tenemos que hacer que «se conozcan». Lo vemos a continuación:

A continuación, en la vista, incluimos todos los componentes necesarios, así:

Por último, en el controlador (app.component.ts) debemos incluir el ScrollSpy de materialize, como vemos en el siguiente fragmento:

El método scrollspy() de materialize tiene algunos parámetros que nos pueden ayudar a configurar su funcionamiento. Los puedes ver en https://materializecss.com/scrollspy.html.

CONCLUYENDO

Acabamos de crear nuestra primera aplicación con materialize integrado en Angular. El código te lo puedes descargar en este enlace. Pruébala, para observar el comportamiento de los enlaces, tanto en modo escritorio como dispositivo móvil, y analiza el código para ver lo simple que es.