Establece una comunicación entre un componente padre con uno hijo para saber qué productos quiere agregar el usuario a su carrito de compras y poder visualizar el total a pagar.
Comunicación componente hijo a padre
Paso 1: Agrégale al componente hijo un @Output() para emitir un mensaje al componente padre cuando el usuario agrega un producto al carrito.
El método addToShoppingCart() emitirá el evento cuando el usuario haga clic en el botón.
<!-- components/producto/producto.component.html --><div><h2>{{ producto.name }}</h2><img[src]="producto.image"width="200px"height="200px"><p>Precio: {{ producto.precio }}</p><button(click)="addToShoppingCart(producto)">Agregar al carrito</button></div>
Paso 2: En el componente padre crea un método para recibir el mensaje, agregarlo al carrito de compras y calcular el monto total a pagar.
// catalogo/catalogo/catalogo.component.ts@Component({selector:'app-catalogo',templateUrl:'./catalogo.component.html',styleUrls:['./catalogo.component.scss']})exportclassCatalogoComponent{publicshoppingCart:Producto[]=[];public total =0;publicproductos:Producto[]=[/* ... */];addProductToCart(p:Producto):void{this.shoppingCart.push(p);this.total+= p.precio;}}
Paso 3: El método addProductToCart() recibe el producto, lo guarda en el array shoppingCart y calcula el total a pagar por el usuario. Puedes imprimir estos valores fácilmente con una interpolación.
<!-- catalogo/catalogo/catalogo.component.ts --><div*ngIf="productos"class="catalogo"><app-producto*ngFor="let p of productos"[producto]="p"(addProduct)="addProductToCart($event)"></app-producto></div><div><h3>Cantidad: {{ shoppingCart.length }}</h3><h3>Total a pagar: {{ total }}</h3></div>
La comunicación de componente es escencial en cualquier aplicación front-end. Es importante saber manipular el envio de información ya sea de forma descendente o ascendente en la jerarquía de componentes.
Contribución creada con los aportes de Kevin Fiorentino.
Comunicación Padre-Hijo con Inputs y Outputs en Angular
menos mal veo comentarios como los de ustedes jaja, es verdad, y algunos no logran dimensionar lo excelente que ha sido el curso, mi pregunta es si están estudiando bien ? o se vuelan los cursos sin generar aprendizaje, es que ami me ha parecido maravilloso hasta ahora, estos cursos y el de manipulación de arrays son la bibilia del frontend jajaja
El tema con esa implementación es que si se quitará un item del carrito el total no se actualizaría o habría que agregar más líneas de código para hacerlo funcionar correctamente
Está muy bueno este curso. Aprendí Angular en Udemy hace un tiempo, pero esta serie de cursos me resulta genial para refrescar algunos conceptos clave.
Buenos días:
Tengo una duda, que es mejor usar, input y outpus o usar redux (ngRX), o simplemente esto depende de la aplicación. En el ejemplo del carrito de compras que seria mejor usar, o cualquier opción esta bien?
Creo que todo depende de lo grande de la aplicación. Y los requerimientos. Pero en lo personal aún no sé cuándo ya es necesario implementar un estado para la aplicación
pregunta, (ojala algún día sea contestada ^.^) ¿Cómo puedo hacer para que al recargar la pagina los productos agregados al carrito entre otras variables no se reinicien o no se borren?(como en linio y otras web de compras) Gracias por sus respuestas
La mejor forma seria con el localStorage del navegador, y al recargar la pagina, cargar los valores del storage, y después de verificar si hay elementos, cargar los componentes.
Así lo haría yo.
Sí, es más correcto usar el método reduce en lugar de hacerlo de esa manera. El método reduce permite reducir un array a un solo valor utilizando una función reductora. En este caso, podrías utilizar reduce para sumar los precios de los productos en el carrito de compras y obtener el total de manera más concisa y eficiente.
myShopingCart:Product[]=[];onAddToShopingCart(product:Product){this.total=this.myShopingCart.reduce((sum, item)=> sum + product.price,0);}
Este código calcula el total de una lista de productos en un carrito de compras. Aquí hay una explicación detallada de lo que sucede en cada parte del código:
this.myShoppingCart se refiere al carrito de compras, que es un objeto que contiene una lista de productos.
reduce() es un método de array que se utiliza para reducir los elementos de un array a un único valor. En este caso, se utiliza para sumar los precios de todos los productos en el carrito.
(sum, item) es una función de reducción que se utiliza para acumular el total de precios. En cada iteración, sum representa el acumulador, es decir, el valor acumulado hasta el momento, y item representa el siguiente elemento en la lista, que en este caso es un objeto que contiene información sobre un producto.
sum + product.price es la operación que se realiza en cada iteración de reduce(). product.price se refiere al precio del producto actual, y se suma al acumulador sum. Al final de la iteración, el nuevo valor de sum se utiliza en la siguiente iteración como el acumulador actualizado.
0 es el valor inicial del acumulador. En la primera iteración, sum se establece en este valor y luego se actualiza en cada iteración.
Por lo tanto, al final de la reducción, this.total contendrá la suma de los precios de todos los productos en el carrito.
El método reduce recibe una función como parámetro. A esa función puede recibir cuatro parametros, que puedes nombrar de "cualquier forma":
El acumulador
El valor actual
El índice actual
El array
Esos parametros los recibe del reduce.
En este caso .reduce((sum, item) => sum + item.price, 0), item es el valor actual que esta procesando el reduce y sum el valor acumulado.
Tu puedes cambiarle el nombre y funcionará igual. Lo importante es la cantidad de parametros que declaras en la función dentro del reduce, pues serán los parametros que recibiras por parte del reduce. 🤓🍍🍍
engo una duda con respecto al EventEmite<Product>()
<Product> es el tipo de dato que le vamos a pasar al EventEmiter como se llama esto referencia Generica?
En TypeScript, <Product> es un ejemplo de lo que se conoce como "tipo genérico" o "parámetro de tipo genérico". Los tipos genéricos permiten que una función o una clase trabajen con diferentes tipos de datos sin tener que definir un tipo específico para cada caso.
En el caso de EventEmitter<Product>, Product es el parámetro de tipo genérico que se utiliza para indicar el tipo de dato que se va a emitir a través del EventEmitter. En otras palabras, Product es un tipo de dato genérico que se reemplaza con un tipo de dato específico en tiempo de ejecución.
Al utilizar tipos genéricos, puedes crear funciones y clases reutilizables que trabajen con diferentes tipos de datos sin tener que escribir una versión separada para cada tipo de dato. Esto hace que tu código sea más genérico y escalable, lo que puede ahorrar tiempo y esfuerzo en el largo plazo.
Si estan con angular 17 y tienen el problema de que no les actualiza la cantidad y el total, la forma que lo pueden solucionar es usando un signal en total. Y en la funcion hacerle el set del reduce al total.
También podemos validar que en el carrito de compras no hayan productos repetidos, comprobando cuando vayamos a añadir un producto al carrito, que dicho producto no haya sido añadido al carrito anteriormente:
addedProducts:Product[]=[];//CARRITO DE COMPRAStotalPrice: number =0;//PRECIO TOTAL DEL CARRITO DE COMPRASonAddToShoppingCart(productAdded:Product){// VERIFICAMOS QUE EL PRODUCTO NO ESTÉ YA DENTRO DEL CARRITO DE COMPRASif(this.addedProducts.includes(productAdded)){console.log("El producto ya ha sido agregado al carrito");}else{this.addedProducts.push(productAdded);//RECALCULAMOS EL VALOR TOTAL DEL PRODUCTO DE COMPRAS://this.totalPrice += productAdded.price;this.totalPrice=this.addedProducts.reduce((sum, product)=> sum + product.price,0);}console.log(this.addedProducts);console.log("TOTAL:",this.totalPrice);}}
Cada día más emocionado con este curso. Muchas gracias Nicolas.
Si se puede hacer metodos para formatear el precio, pero Angular es un framework muy poderoso que te permite crear tus propias funciones y métodos personalizados que se pueden usar en cualquier lugar de tu aplicación. Una forma común de crear una función para formatear un número es crear un "pipe" (tubería) personalizado.
import{Pipe,PipeTransform}from'@angular/core';@Pipe({name:'formatNumber'})exportclassFormatNumberPipeimplementsPipeTransform{transform(value: number): string {// Convertir el número a una cadena con dos decimalesconst formattedNumber =Number(value).toFixed(2);// Agregar comas como separadores de milesconst parts = formattedNumber.toString().split('.'); parts[0]= parts[0].replace(/\B(?=(\d{3})+(?!\d))/g,",");return parts.join('.');}}
En el ejemplo anterior, se crea una clase de pipe personalizado llamada FormatNumberPipe. El método transform acepta un valor numérico como entrada y devuelve una cadena de texto con el número formateado con comas como separadores de miles y dos decimales.
Para usar el pipe en tu aplicación, solo tienes que incluirlo en el módulo donde quieras usarlo y luego llamarlo desde tu plantilla:
htmlCopy code
<!--Ejemplo de uso del pipe en una plantilla --><p>El precio total es:{{ total | formatNumber }}</p>
En este ejemplo, total es el valor numérico que quieres formatear y formatNumber es el nombre del pipe personalizado que acabas de crear.
Aun que claro, Angualr ya tiene pipes predefinidos para algunos casos especificos, te dejo el link donde los puedes ver sin necesidad de tener que crear la clase Pipes Angular