Al trabajar con aplicaciones web, a menudo ocurre que los datos que recibimos desde el backend no son del todo adecuados para el frontend. Pueden faltar campos necesarios para mostrar información o realizar cálculos adicionales. En estos casos, es esencial entender cómo transformar peticiones en Angular para enriquecer los datos adicionando o calculando atributos nuevos antes de presentarlos al usuario.
¿Cómo se añade un atributo desde el frontend?
Para añadir atributos calculados en el frontend, el método getAllProducts será nuestra base de trabajo. Imaginemos que deseamos añadir un campo adicional llamado taxes a cada producto, que no está incluido en la respuesta del backend pero es crucial para nuestros usuarios.
Declarar el nuevo atributo:
Primero, indicaremos que cada product tendrá un campo adicional llamado number, el cual será opcional. Esto se realiza en la definición del producto.
exportinterfaceProduct{ id:string; name:string; price:number;// Nuevo campo opcionalnumber?:number;}
Calcular el nuevo atributo en el servicio:
Luego, usaremos el operador map del servicio para calcular este nuevo atributo.
getAllProducts(){returnthis.http.get<Product[]>(this.apiURL).pipe(map(products => products.map(product =>({...product, taxes: product.price*0.19// Suponiendo un IVA del 19%}))));}
¿Cuál es el papel del operador map en la transformación?
El operador map en Angular es fundamental para transformar datos observables. Al recibir un array de productos, podemos aplicarle nuevas transformaciones, convirtiendo cada respuesta en algo más acorde a nuestras necesidades.
Transformaciones observables: Esto implica analizar la respuesta del backend y modificarla antes de su consumo.
Transformaciones de elementos: Una segunda transformación utiliza el map nativo de JavaScript para aplicar cambios específicos en cada elemento del array.
Esta fluidez y adaptabilidad pueden ser vitales cuando los requisitos de negocio cambian o el diseño de la UI requiere información específica.
¿Cómo mejorar la presentación de datos con pipes?
Cuando calculamos valores como el de impuestos, es común enfrentarse a la presentación de números con varios decimales. Angular provee pipes que son herramientas útiles para transformar la salida de manera visualmente atractiva.
Uso del pipe de moneda:
Podemos usar el pipe especial para manejar la presentación de monedas, asegurando que el valor se muestre adecuadamente en la interfaz, con el formato regional correcto.
Este formato no solo mejora la legibilidad de la información, sino que también aumenta la usabilidad de la aplicación al adaptar los datos a las expectativas de los usuarios.
¿Cuáles son las mejores prácticas de transformación?
Es importante recordar que la lógica de negocio debe residir en los servicios, para que el componente se dedique simplemente a su responsabilidad principal: renderizar y gestionar la interacción con el usuario. Esto facilita la reutilización de código y mantiene el componente limpio y manejable. Además:
Aislar la lógica en el servicio: Esto permite que la transformación o cualquier operación sobre los objetos de datos sea más mantenible.
Reutilizar lógica de transformación: Facilita la integración con otros componentes que puedan requerir datos de manera similar.
En fin, el uso inteligente de estas transformaciones en Angular puede optimizar el proceso de desarrollo, asegurando al mismo tiempo que la aplicación se mantenga flexible y preparada para escalar o adaptar requisitos futuros. ¡Sigue aprendiendo y viendo cómo estos conceptos pueden aplicarse en otros contextos!
Si no les sale el el valor en su html... prueben pondiendo el codigo en el metodo getProductsByPage
Muchas gracias.
Muchas gracias...
Hay un error en esta clase en la parte de product?.taxes
lo que hace el ? en product? es validar si el objeto product existe, entonces usa la propiedad .taxes, por tanto product?.taxes no va a generar ningun error.
Lo ideal seria usar el ?? de la siguiente forma: product.taxes ?? '' es decir, si la propiedad es null o undefined coloca un string vacio.
en que momeno se puede usar el ??
Siguiendo este curso una opcion podria ser las imagenes. Si product.images viene null o undefined ahi si aplica y querdaria asi: product.images?.length
Funcionó ✅
No es tan error. En la consola sale más como un warning pero el código compila y corre bien. Ese warning aparece desde la penúltima versión de TypeScript además que el propio IDE ya identifica esto, pero para ahorrarse un dolor de cabeza al ver al IDE quejarse igual que NodeJS y TS, product.taxes ?? '' es la mejor opción.
recordar que en el componente products, en oninit cargamos los productos por medio del servicio getProductsByPage, por ende es en este servicio es donde debemos usar el map dentro del pipe para que este agregue el elemento taxes que en los productos queremos visualizar. ( el pipe en getAllProducts ya no se usa a este punto).
Gracias, me funciono usando el pipe en getProductsByPage
RxJS map() operator is a transformation operator used to transform the items emitted by an Observable by applying a function to each item.
Documentación
A veces puede ser necesario hacer transformaciones a la respuesta de una petición, para poner ejemplo agregar datos para complementar la información que entrega el backend.
RXJS .map() → Es un operador que permite tomar cada uno de los valores que lleguen en el observable y aplicarles una transformación.
// Obtener los productos desde la APIgetProducts(limit?:number, offset?:number){...returnthis.http.get<Product[]>(this.apiUrl,{ params }).pipe(map(products => products.map(item =>{return{...item, taxes:.19* item.price}})))}
products → Agrupa la respuesta del observable, esta es un array. Luego se usa un map nativo para agregar el atributo taxes a cada objeto dentro de products.
Luego en la vista del componente se podría renderizar esta propiedad:
<p>Valor IVA: {{ product?.taxes | currency }}</p>
El operador de optional chaining (?) permite que la propiedad solo se muestra si su valor no es nulo.
Hola,
He seguido la clase, y agregado el código para las taxes, pero no renderiza el valor y no da error al compilar. Algun@ a tenido el mismo resultado.
Gracias de antemano.
Hola John 👋🏻
¿puedes compartir un print de pantalla para ayudarte?
Hola Jesús, si claro, estuve repasando nuevamente la clase por si se me hubiera pasado algo, pero no logro encontrar el error, les comparto el código:
product.model.ts
product.service.ts
producto.component.html
browser
Muchas gracias de antemano.
Creo que vi esta misma notacion cuando comence a trabajar y al fin puedo decir que la entiendo bien
No es lo mas explicito del mundo, pero lo entiendo, algo he avanzado en mi js, jaja
Te hago una consulta! Ya vi anteriormente el uso de "...item" cuando se trata de recorrer o agregar algo a un array. Cual sería el motivo de el "..."? Gracias!
a tu operador map() le hace falta un return. Diciendo, de esta lista de productos, devuelve el resultado que retorna el nuevo arreglo del map() convencional (que no es RxJS).
Siempre recuerda que un map() sea el operador de RxJS o el convencional, debe retornar algo. Y si abres un scope donde meterás lógica deberás colocar un return
Muchas gracias, sabes gracias a tu respuesta me di cuenta de otra cosa super básica, estaba utilizando getProductByPage() y nunca llegue a usar la función getAllProducts(), por eso no salia lo de los taxes, y por ende el map no corria xD
El operador RxJS map() es un operador de transformación que se utiliza para transformar los elementos emitidos por un Observable aplicando una función a cada elemento.
Y si quisiera agregar "taxes" a mi objeto product cuando abro el detalle... ¿como le haría? Ya que ya no es un array para usar map, ahora el request me devuelve el objeto de product. Quisiera saber como manipular un objeto y agregarle una nueva variable
Tengo un problema con mi codigo, si le mando a ejecutar este corre sin problema, de igual forma le mande un ng lint y todo va bien. este es
getProduct(id: string) {
return this.http.get<Producto>(${this.apiUrl}/${id}).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status == HttpStatusCode.Conflict) {
return throwError('Algo esta fallando en el Server');
}
if (error.status == HttpStatusCode.NotFound) {
return throwError('El producto no existe');
}
if (error.status == HttpStatusCode.Unauthorized) {
//erro 401 cuando uno no esta autorizado
return throwError('No estas permitido para ingrasar');
}
return throwError('Ups algo salio mal');
})
);
}
throwError sale tachado con una linea en el medio de la palabra. Ayer corria perfecto y hoy que basicamente no le he ehcho nada ya no salen las imagenes de la tienda al comienzo. Que podria ser
no me imprime el calculo de los taxes en el product html :c
alguien tiene una idea del porque ?
Noto que tienes algunos detalles con el typo , como la palabra let junto al igual que despues de limit&& y algunos otros detallitos como un punto despues del this.apiUrl te paso el como deberia estar el getAllProducts