Botón reusable que engloba todas las opciones de botones de Angular Matrerial; usando @swich para iterar y elegir el adecuado.
Hemos creado un carrusel con swiperjs; una biblioteca exclusiva para carruseles, el repositorio muestra el código completo para un primer carrusel completamente reusable, además podrás personalizarlo usando los demos de Swiper Js.
Botón de cambio de temas de oscuro a claro usando angular material theme, con lógica directa en el componente completamente standalone, funcionando.
Uso de ChangeDetectionStrategy.OnPush:
Qué es: Configura la estrategia de detección de cambios del componente para que Angular solo lo revise cuando sus @Input()s cambian (por referencia), un evento del componente ocurre, o cuando sus Signals (que es tu caso) se actualizan.
Por qué es clave: Reduce drásticamente la cantidad de veces que Angular tiene que verificar el componente, mejorando el rendimiento general de tu aplicación, especialmente en árboles de componentes grandes.
Cómo aplicarlo: Añade changeDetection: ChangeDetectionStrategy.OnPush en el decorador @Component.
Gestión de Estado con Signals:
Qué es: Utiliza signal() de Angular para manejar el estado reactivo del componente (como products y cargando).
Por qué es clave: Las Signals son el mecanismo de reactividad moderno y altamente optimizado de Angular. Se integran perfectamente con OnPush, asegurando que solo se re-renderice lo necesario cuando el valor de una Signal cambia.
Cómo aplicarlo: Declara tus propiedades reactivas como Signals, por ejemplo: public products = signal<CardInterface[]>([]);.
Centralización de la Lógica de Datos en un Servicio Firestore:
Qué es: Inyecta un servicio dedicado (como tu firestoreService) que contenga todos los métodos para interactuar con Firestore (CRUD).
Por qué es clave:
Modularidad: Separa la lógica de la UI de la lógica de acceso a datos.
Reutilización: Evitas duplicar código de consulta de base de datos en múltiples componentes.
Mantenimiento: Si la API de Firebase cambia o necesitas modificar cómo interactúas con la base de datos, solo lo harás en un lugar.
Cómo aplicarlo: Inyecta el servicio en el constructor (o usando inject()): firestoreService = inject(Firestore); y luego usa sus métodos como this.firestoreService.getCollection().
Lectura Única de Datos (getDocs) para Contenido Estático:
Qué es: En lugar de onSnapshot (oyente en tiempo real), usa el método de tu servicio que internamente llama a getDocs().
Por qué es clave: Minimiza el consumo de lecturas en Firestore al obtener los datos una sola vez por visita al componente, lo cual es ideal para colecciones que no cambian con frecuencia. Evita el costo de lecturas incrementales y la necesidad de gestionar suscripciones.
Cómo aplicarlo: Llama a un método asíncrono de tu servicio (ej., this.firestoreService.getCollection()) desde ngOnInit.
Manejo Asíncrono con async/await:
Qué es: Usa las palabras clave async y await para manejar las operaciones asíncronas de Firestore (como getCollection).
Por qué es clave: Hace que el código asíncrono sea mucho más legible y fácil de manejar, pareciéndose a un código síncrono.
Cómo aplicarlo: Declara el método que realiza la operación de datos como async y usa await antes de las llamadas que devuelven Promesas.
Indicadores de Carga y Manejo Básico de Errores:
Qué es: Muestra un indicador de progreso (cargando Signal) mientras se obtienen los datos y maneja posibles errores con un bloque try...catch.
Por qué es clave: Mejora la experiencia del usuario al informarle que algo está sucediendo y previene que la aplicación se bloquee si hay un problema al obtener los datos.
Cómo aplicarlo: Establece cargando.set(true) al inicio de la operación de datos y cargando.set(false) al final, tanto en el try como en el catch.
Al aplicar estos principios en tus futuros componentes, te asegurarás de mantener un alto nivel de optimización y una experiencia de usuario fluida en toda tu aplicación Angular.
EJEMPLO DEL COMPONENTE OPTIMIZADO ANGULÑAR Y ANGULAR MATERIAL
import { Component, inject, signal, OnInit, ChangeDetectionStrategy } from '@angular/core'; // Importamos ChangeDetectionStrategy
import { Card, CardInterface } from '../../components/card/card';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { Firestore } from '../../firebase/firestore'; // Importamos tu servicio Firestore
@Component({
selector: 'app-tacos',
standalone: true,
imports: [
Card,
MatProgressBarModule
],
templateUrl: './tacos.html',
styleUrl: './tacos.css',
changeDetection: ChangeDetectionStrategy.OnPush // ¡Este es el cambio clave para optimización!
})
export class Tacos implements OnInit {
public category = 'tacos';
// Inyectamos tu servicio Firestore que ahora contiene los métodos CRUD
firestoreService = inject(Firestore);
// products es un signal para manejar la lista de productos
public products = signal<CardInterface[]>([]);
// cargando es un signal para mostrar/ocultar el progress bar
public cargando = signal(true);
// Método para obtener los productos utilizando el servicio Firestore
private async getProducts() {
this.cargando.set(true); // Mostrar indicador de carga
this.products.set([]); // Limpiar productos existentes mientras carga
try {
// Usamos el método getCollection de tu servicio firestoreService
// Le pasamos la ruta de la colección y los filtros deseados
const items = await this.firestoreService.getCollection<CardInterface>('Products', [
{ field: 'category', operator: '==', value: this.category }
]);
// Actualizamos la signal con los productos obtenidos
this.products.set(items);
this.cargando.set(false); // Ocultar indicador de carga
} catch (error) {
console.error('Error al obtener productos:', error);
this.cargando.set(false); // Asegúrate de ocultar el indicador incluso con errores
// Aquí podrías añadir lógica para mostrar un mensaje al usuario
}
}
// Método del ciclo de vida que se ejecuta cuando el componente se inicializa
ngOnInit() {
this.getProducts(); // Llamamos al método para obtener los productos al inicio
}
}
BOTONES
CARRUSELES
PAGES
CARDS
SCROLLBAR
IMAGES
BANNERS
TOOLBAR