Escuchar el evento scroll en Angular es más sencillo de lo que parece. Te voy a explicar las distintas maneras que te ofrece Angular para conseguirlo con apenas 2 líneas de código.
Scroll dentro de un componente
Imagina que tienes un elemento cuyo contenido es mayor que su altura, de forma que puedes hacer scroll en su interior. Vamos a llamar a este elemento <scrollable-component>
.
Angular te ofrece 2 formas muy sencillas para atender a ese evento scroll del componente.
Tip: Para que un componente entienda que se está haciendo scroll en su interior, es necesario que su propiedad CSS
display
sea tipo block-level, es decir:block
,inline-block
,grid
oflex
.
1) suscripción externa, desde el template padre
Puedes atender ese evento de scroll desde fuera del componente, es decir, desde su componente padre.
Solo necesitas usar un event binding sobre su propiedad scroll, como si de un click se tratara. Así:
<scrollable-component (scroll)="doSomethingOnScroll($event)">
<item></item>
<item></item>
<!-- some more items -->
</scrollable-component>
De este modo, cuando estés haciendo scroll dentro de <scrollable-component>
, se llamará al método doSomethingOnScroll()
del componente que lo contiene.
2) suscripción interna, desde el componente
Puedes suscribirte al evento de scroll del componente desde su propio controlador, usando un HostListener
. Así:
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'scrollable-component',
templateUrl: './scrollable.component.html',
styleUrls: ['./scrollable.component.css']
})
export class ScrollableComponent {
@HostListener("scroll", ['$event'])
doSomethingOnInternalScroll($event:Event){
let scrollOffset = $event.srcElement.scrollTop;
console.log("scroll: ", scrollOffset);
}}
}
De este modo, a cada evento de scroll del componente ScrollableComponent, se ejecutará el método doSomethingOnInternalScroll()
.
Componentes Angular Nivel PRO
Evento scroll global
Hasta ahora veías como suscribirte a un evento de scroll limitado a un componente, pero por supuesto, podrías querer escuchar el evento scroll global, el típico window.scroll
, para que nos entendamos.
Angular te da acceso al evento scroll global de forma análoga a los dos ejemplos anteriores, mediante
window:scroll
.
De este modo puedes:
1) Suscribirte a window:scroll
desde el template
Se me hace un poco extraño, pero puedes suscribirte desde un elemento cualquiera del template, así:
<div (window:scroll)="doSomethingOnWindowScroll($event)">
</div>
<!-- some more stuff -->
2) Suscribirte a window:scroll
desde el componente
Para mi esta opción tiene bastante más sentido: Suscribirte con un @HostListener
desde el componente en que quieres escuchar el evento de scroll global:
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'my-component',
templateUrl: './my.component.html',
styleUrls: ['./my.component.css']
})
export class MyComponent {
@HostListener("window:scroll", ['$event'])
doSomethingOnWindowsScroll($event:Event){
let scrollOffset = $event.srcElement.children[0].scrollTop;
console.log("window scroll: ", scrollOffset);
}
}
Reflexiones personales
Angular te ofrece de partida unos mecanismos muy sencillos para escuchar eventos de scroll. ¿Pero que pasa si quieres reducir la frecuencia con la que se llama el evento? Ahí amigo, la cosa se complica.
En próximos artículos explicaré como crear un servicio de scroll con debouncing para evitar interrupciones demasiado frecuentes durante el scroll.
¿Te ha gustado este artículo? No te cortes, déjame un comentario y ayúdame a compartirlo 😉
Saludos excelente trabajo el que realizas, oye tal vez puedas ayudarme estoy realizando mi aplicación pero tengo un problema o dos el primero es que cuando voy de una pagina a otra no va al inicio de la pagina es decir si me encuentro en el home y luego hago link a servicio me lleva hasta la mitad o depende de donde me encuentre en el home, no se si me explico quisiera me llevara al inicio de la pagina servicio y así con el resto.El otro es que cuando mi app carga el slider esta bien pero al explorar la app y regresar al home ya el slider no carga hay una manera de recarga la pagina todo esto en Angular gracias de antemano
Para el scroll usa window.scrollTo(0, 0);
Saludos Enrique , gracias por el tutorial, sin embargo en la línea
let scrollOffset = $event.srcElement.children[0].scrollTop;
el compilador me indica:
La propiedad ‘children’ no existe en el tipo ‘EventTarget’.
Sabes porqué puede ser?
Me pasa lo mismo que a Johan Nieto, alguien sabe por que ?
Hola me pararece que esto sucede porque srcElement esta depreciado
Esto tal vez tiene que ver con el tipado de TS, no recuerdo bien, pero creo que especificando el se resuelve
Hola!,
Yo estoy intentando implementar un botón que haga el scroll hasta top, pero lo estoy haciendo desde una directiva, ya que la idea es usar este botón en otros componentes, desafortunadamente el evento scroll no me está regresando nada aunque haga scroll :/.
button: HTMLElement;
ngAfterViewInit() {
this.button = document.createElement(‘button’);
this.button.classList.add(‘scroll-to-top’);
this.button.addEventListener(‘click’, () => {
this.elRef.nativeElement.scrollIntoView( {behavior: ‘smooth’} ); // con esto hago scroll hasta el div donde anadí la directiva
});
this.elRef.nativeElement.appendChild(this.button);
this.elRef.nativeElement.addEventListener(‘scroll’, () => console.log(‘estoy haciendo scroll’);
}
Hola! Yo me cree un comp bien sencillo con un tag button, al que simplemente agrego este metodo al dar click:
toTheTop() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
Gracias Karla, tu idea me funciono mucho para lo que necesitaba
Hola alguien ya corrigio el error del deprecado? $event.srcElement.children[0].scrollTop, srcElement is deprecated
Hola, para los que aun tienen problemas, encontre esta otra solucion, me sirvio excelente:
@HostListener(‘window:scroll’, [‘$event’])
track(event) {
console.debug(«Scroll Event», window.pageYOffset );
}
Saludos