Temas practicados en este proyecto:
LazyLoad
Separación de rutas
Rutas hijas
Variables de entorno de Angular
Angular CLI
inputs
Comunicación entre componentes
RouterOutlets anidados
Señales
Propiedades de componentes
Tailwind
Manejo de rutas dinámicas
Manejo de LocalStorage
Observables a Señales
Reutilización de componentes
Peticiones HTTP
Manejo de caché
Mapeo de información
Preservar estado del scroll
Hacer scroll infinito
Diseño masonry
Técnicas y herramientas para depurar
Trending Page Component:
import { Component, ElementRef, inject, viewChild } from "@angular/core";
import { GifService } from "../../services/gif.service";
@Component({
selector: "gifs-trending-page",
templateUrl: "./trending-page.component.html",
styles: ``,
})
export default class TrendingPageComponent {
gifService = inject(GifService);
trendingGifsInfinite = this.gifService.trendingGifs();
scrollDivRef = viewChild<ElementRef<HTMLDivElement>>("groupDiv");
constructor() {
this.gifService.trendingGifsGroup();
}
onScroll(e: Event) {
const scrollDiv = this.scrollDivRef()?.nativeElement;
if (!scrollDiv) return;
const scrollTop = scrollDiv.scrollTop;
const clientHeight = scrollDiv.clientHeight;
const scrollHeight = scrollDiv.scrollHeight;
// Pixels before the bottom to trigger the infinite scroll
// With this, you can adjust the distance from the bottom to trigger the infinite scroll
const fireLoadingBefore = 300;
const isAtBottom: boolean = scrollTop + clientHeight + fireLoadingBefore >= scrollHeight;
if (isAtBottom) {
this.gifService.loadTrendingGifs();
}
}
}
Service:
@Injectable({
providedIn: "root",
})
export class GifService {
private http = inject(HttpClient);
private router = inject(Router);
trendingGifs = signal<Gif[]>([]);
trendingGifsLoading = signal(false);
private trendingPage = signal(0);
// other methods
loadTrendingGifs(): void {
// While loading trending gifs don't load more, don't request more
if (this.trendingGifsLoading()) return;
// when loading is false, set loading to true for the next request
this.trendingGifsLoading.set(true);
this.http
.get<GiphyResponse>(`${environment.giphyBaseUrl}/gifs/trending`, {
params: {
api_key: environment.giphyApiKey,
limit: "20",
offset: (this.trendingPage() * 20).toString(),
},
})
.subscribe((resp) => {
const newGifs = GifMapper.mapGiphyItemsToGifArray(resp.data);
this.trendingGifs.update((currentGifs) => [...currentGifs, ...newGifs]);
this.trendingPage.update((currentPage) => currentPage + 1);
this.trendingGifsLoading.set(false);
});
}
}
Explicación:
Estos tres elementos (scrollTop, clientHeight, scrollHeight) son fundamentales para implementar el scroll infinito en una página web. Entender cómo interactúan te permitirá detectar cuándo el usuario ha llegado (o está cerca) del final de un contenedor con scroll. ¡Claro! Estos tres elementos (scrollTop, clientHeight, scrollHeight) son fundamentales para implementar el scroll infinito en una página web. Entender cómo interactúan te permitirá detectar cuándo el usuario ha llegado (o está cerca) del final de un contenedor con scroll. Vamos a desglosarlos:
La lógica principal detrás del scroll infinito es detectar cuándo el usuario está lo suficientemente cerca del final del contenido visible para que se dispare la carga de más elementos antes de que llegue al final absoluto. Esto se logra comparando estos tres valores.
Una condición común para disparar la carga de más contenido es cuando la suma del scrollTop (lo que ya se ha desplazado) y el clientHeight (lo que actualmente se ve) es mayor o igual a una cierta distancia del scrollHeight (la altura total).
Por ejemplo:
const scrollDiv = document.getElementById('tuDivConScroll');
const umbral = 20; // Pixeles antes del final para cargar más
scrollDiv.addEventListener('scroll', () => {
const scrollTop = scrollDiv.scrollTop;
const clientHeight = scrollDiv.clientHeight;
const scrollHeight = scrollDiv.scrollHeight;
// Comprobamos si estamos cerca del final
if (scrollTop + clientHeight >= scrollHeight - umbral) {
// Aquí es donde llamas a tu función para cargar más datos de la API
cargarMasElementos();
}
});
function cargarMasElementos() {
console.log('¡Cargando más elementos!');
// Aquí iría tu lógica para hacer la petición a la API y añadir los nuevos elementos al DOM
}
Desglose de la condición scrollTop + clientHeight >= scrollHeight - umbral:
scrollTop + clientHeight: Representa la posición actual del borde inferior del área visible del contenedor. Es decir, cuánta distancia total se ha recorrido desde la parte superior hasta la parte inferior de la ventana visible. scrollHeight - umbral: Representa un punto que está umbral píxeles antes del final absoluto del contenido. Cuando la posición del borde inferior visible (scrollTop + clientHeight) alcanza o sobrepasa este umbral, significa que el usuario está a umbral píxeles o menos del final del contenido, y es el momento de cargar más elementos.
Consideraciones importantes:
Umbral: El valor del umbral es crucial. Si es demasiado pequeño, podrías hacer demasiadas llamadas a la API muy seguidas. Si es demasiado grande, el usuario podría llegar al final antes de que se carguen los nuevos elementos. Experimenta para encontrar un valor adecuado para tu aplicación. Control de carga: Asegúrate de implementar un mecanismo para evitar múltiples llamadas a la API mientras se están cargando los datos. Puedes usar una bandera (boolean) para indicar si una carga está en curso. Fin del contenido: Debes tener una forma de saber cuándo has cargado todos los elementos de la API para dejar de intentar cargar más. Rendimiento: Cargar grandes cantidades de datos de golpe puede afectar el rendimiento. Considera cargar los datos en lotes razonables. Experiencia del usuario: Proporciona alguna indicación visual (como un spinner o un mensaje) mientras se están cargando los nuevos elementos para que el usuario sepa que la aplicación está trabajando.