Introducción a Angular y Fundamentos

1

Aprende Angular 17

2

Creando tu primer proyecto en Angular

3

Implementando estilos

4

Mostrando elementos

5

Property Binding en Angular

6

Event Binding: click y doble click

7

Event binding: keydown

8

Modelo de reactividad con Signals

9

Creando un Signal en Angular

Estructuras de control en Angular

10

Directivas de control

11

Uso de ngFor

12

ngFor para objetos

13

Update Tasks

14

Uso de ngIf

15

Uso de ngSwitch y ngSwitchDefault

16

Controlando un input

17

Manejo de formularios en Angular

Alistando tu aplicación para producción

18

Estilos al modo Angular

19

Clases en Angular

20

Editing mode

21

Estados compuestos con computed

22

Usando effect para localStorage

23

Uso de ngbuild

24

Despliegue con Firebase Hosting

25

Nueva sintaxis en Angular

26

Directivas @For, @switch

27

Migrando a la nueva sintaxis de Angular v17

Componentes Reutilizables y Comunicación

28

Construyendo un e-commerce en Angular

29

Componentes en Angular

30

Mostrando los componentes

31

Angular DevTools

32

Uso de Inputs en Angular

33

Uso de Outputs en Angular

34

Componentes para Producto

Ciclo de vida de los componentes

35

Ciclo de vida de componentes

36

Ciclo de vida de componentes: ngOnChanges

37

Ciclo de vida de componentes: ngOnInit

38

Detectando cambios en los inputs

39

Evitando memory leaks con ngDestroy

40

Audio player con ngAfterViewInit

41

Creando la página "about us" o "conócenos"

Mejorando la interfaz del producto

42

Creando componente de productos

43

Creando el Header

44

Creando el carrito de compras

45

Comunicación padre e hijo

46

Calculando el total con ngOnChanges

47

El problema del prop drilling

48

Reactividad con signals en servicios

49

Entendiendo la inyección de dependencias

Integración y Datos

50

Obteniendo datos una REST API

51

Importaciones cortas en Typescript

52

Pipes en Angular

53

Construyendo tu propio pipe

54

Utilizando librerías de JavaScript en Angular

55

Conociendo las directivas

56

Deployando un proyecto en Vercel

Enrutamiento y Navegación

57

Ruta 404

58

Uso del RouterLink

59

Vistas anidadas

60

Uso del RouterLinkActive

61

Detalle de cada producto

62

Obteniendo datos del producto

63

Galería de imagenes

64

Detalle de la galería

Perfeccionando tu e-commerce

65

Mostrando categorias desde la API

66

Url Params

67

LazyLoading y Code Splitting

68

Aplicando LazyLoading

69

Prefetching

70

Usando la nueva sintaxis de Angular 17

71

Lanzando tu aplicación a producción

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Construyendo tu propio pipe

53/71
Recursos

Aportes 5

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

## Reto ```typescript transform(value: string): string { const date = new Date(value).getTime(); // Not a valid date if (isNaN(date)) { return ''; } const now = Date.now(); const diffInTime = now - date; const diffInHours = Math.round(diffInTime / (1000 \* 3600)); if (diffInHours < 24) { return this.applyFormat(diffInHours, 'hour'); } const diffInDays = Math.floor(diffInHours / 24); if (diffInDays < 30) { return this.applyFormat(diffInDays, 'day'); } const diffInMonths = Math.floor(diffInDays / 30); if (diffInMonths < 12) { return this.applyFormat(diffInDays, 'month'); } const diffInYears = Math.floor(diffInMonths / 12); return this.applyFormat(diffInYears, 'year'); } } ```
Hice esta función un poco larga pero funciona ```typescritp timeAgo(value: Date): String { const now = new Date(); const seconds = Math.round(Math.abs((now.getTime() - value.getTime()) / 1000)); const minutes = Math.round(Math.abs(seconds / 60)); const hours = Math.round(Math.abs(minutes / 60)); const days = Math.round(Math.abs(hours / 24)); const months = Math.round(Math.abs(days / 30.416)); const years = Math.round(Math.abs(days / 365)); if (Number.isNaN(seconds)) { return 'Today'; } else if (seconds <= 45) { return 'a few seconds ago'; } else if (seconds <= 90) { return 'a minute ago'; } else if (minutes <= 45) { return minutes + ' minutes ago'; } else if (minutes <= 90) { return 'an hour ago'; } else if (hours <= 22) { return hours + ' hours ago'; } else if (hours <= 36) { return 'a day ago'; } else if (days <= 25) { return days + ' days ago'; } else if (days <= 45) { return 'a month ago'; } else if (days <= 345) { return months + ' months ago'; } else if (days <= 545) { return 'a year ago'; } else { // (days > 545) return years + ' years ago'; } } } ```
**Solución al reto:** Inicialmente, como en el modelo `product` la propiedad `creationAt` está tipada como `string | undefined`, debemos eliminar el tipo `undefined` o utilizar el operador de coalescencia nula (`??`) en el binding, de manera que el código quede de la siguiente forma: ```ts {{product.creationAt ?? '' | timeAgo }} ```transform(value: string): string {    const currentDate = new Date();  // Fecha actual    const receiptDate = new Date(value)    const elapsedMilliseconds = currentDate.getTime() - receiptDate.getTime();     const elapsedDays = Math.floor(elapsedMilliseconds / (1000 \* 60 \* 60 \* 24));    const elapsedHours = Math.floor((elapsedMilliseconds % (1000 \* 60 \* 60 \* 24)) / (1000 \* 60 \* 60));    const elapsedMinutes = Math.floor((elapsedMilliseconds % (1000 \* 60 \* 60)) / (1000 \* 60));     return `${elapsedDays} días, ${elapsedHours} horas y ${elapsedMinutes} minutos`;  }Una vez hecho esto, procedemos a implementar el algoritmo de transformación en el pipe. Este algoritmo calculará el tiempo transcurrido desde una fecha específica hasta el día de hoy, utilizando el objeto `Date` de JavaScript y aplicando algunas operaciones matemáticas. ```ts transform(value: string): string { const currentDate = new Date(); const receiptDate = new Date(value) const elapsedMilliseconds = currentDate.getTime() - receiptDate.getTime(); const elapsedDays = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24)); const elapsedHours = Math.floor((elapsedMilliseconds % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const elapsedMinutes = Math.floor((elapsedMilliseconds % (1000 * 60 * 60)) / (1000 * 60)); return `${elapsedDays} días, ${elapsedHours} horas y ${elapsedMinutes} minutos`; } ``` `const currentDate = new Date();` -> Obtenemos la fecha actual `const receiptDate = new Date(value)` -> Convertimos la fecha recibida al tipo `Date`. `const elapsedMilliseconds = currentDate.getTime() - receiptDate.getTime();` -> Calcula la diferencia en milisegundos entre la fecha actual y la fecha dada. `elapsedDays, elapsedHours, elapsedMinutes` -> Convierte la diferencia en días, horas y minutos usando matemáticas básicas.
Esta es mi solución de time-ago fue utilizando un stack, aunque fue una solución muy extensa la verdad. Este es mi codigo. ```js import { Pipe, PipeTransform } from '@angular/core'; interface StackNode { next(): StackNode, isNext() : Boolean, get(): String } enum TimeAgoEnum { SECONDS = 1000, MINUTES = 60, HOURS = 60, DAYS = 24, WEEK = 7, MONTH = 4 } enum TimeLimitEnum { SECONDS = 60, MINUTES = 60, HOURS = 24, DAYS = 7, WEEK = 4, MONTH = 12 } interface Data { v: TimeAgoEnum, t: 'Just Now' | 'Minutes' | 'Hours' | 'Days' | 'Weeks' | 'Months', l: TimeLimitEnum, } class TimeAgo implements StackNode { params: Data[] = [ { v: TimeAgoEnum.SECONDS, t: 'Just Now', l: TimeLimitEnum.SECONDS}, { v: TimeAgoEnum.MINUTES, t: 'Minutes', l: TimeLimitEnum.MINUTES}, { v: TimeAgoEnum.HOURS, t: 'Hours', l: TimeLimitEnum.HOURS}, { v: TimeAgoEnum.DAYS, t: 'Days', l: TimeLimitEnum.DAYS}, { v: TimeAgoEnum.WEEK, t: 'Weeks', l: TimeLimitEnum.WEEK}, { v: TimeAgoEnum.MONTH, t: 'Months', l: TimeLimitEnum.MONTH} ] idxParams = -1; createdAt! : number; diffTime! : number; shouldContinue = true; resultTimeAgo = ""; constructor(createdAt: number) { this.createdAt = createdAt; this.diffTime = Math.floor(Date.now() - createdAt); } next(): StackNode { if (this.shouldContinue == false) throw new Error('Cannot next') const currenParam = this.params[this.idxParams]; const compare = Math.floor(this.diffTime / currenParam.v.valueOf()); if (compare <= 0 || compare < currenParam.l.valueOf()) this.shouldContinue = false; if (compare > 0) this.diffTime = compare; this.resultTimeAgo = `${this.diffTime} ${currenParam.t} ago!`.toLowerCase(); return this; } isNext(): Boolean { this.idxParams += 1; if (this.idxParams == this.params.length) return false; return this.shouldContinue; } get(): string { return this.resultTimeAgo; } } @Pipe({ name: 'timeAgo', standalone: true }) export class TimeAgoPipe implements PipeTransform { transform(value: string, ...args: string[]): string { console.log(`${value}`); const timeAgo = new TimeAgo(Number(value)) while (timeAgo.isNext()) timeAgo.next(); return timeAgo.get(); } } ```import { Pipe, PipeTransform } from '@angular/core'; *interface* <u>StackNode</u> { next(): <u>StackNode</u>, isNext() : <u>Boolean</u>, get(): <u>String</u>} *enum* <u>TimeAgoEnum</u> { SECONDS = 1000, MINUTES = 60, HOURS = 60, DAYS = 24, WEEK = 7, MONTH = 4} *enum* <u>TimeLimitEnum</u> { SECONDS = 60, MINUTES = 60, HOURS = 24, DAYS = 7, WEEK = 4, MONTH = 12} *interface* <u>Data</u> { v: <u>TimeAgoEnum</u>, t: 'Just Now' | 'Minutes' | 'Hours' | 'Days' | 'Weeks' | 'Months', l: <u>TimeLimitEnum</u>,} *class* <u>TimeAgo</u> implements *<u>StackNode</u>* { params: <u>Data</u>\[] = \[ { v: TimeAgoEnum.SECONDS, t: 'Just Now', l: TimeLimitEnum.SECONDS}, { v: TimeAgoEnum.MINUTES, t: 'Minutes', l: TimeLimitEnum.MINUTES}, { v: TimeAgoEnum.HOURS, t: 'Hours', l: TimeLimitEnum.HOURS}, { v: TimeAgoEnum.DAYS, t: 'Days', l: TimeLimitEnum.DAYS}, { v: TimeAgoEnum.WEEK, t: 'Weeks', l: TimeLimitEnum.WEEK}, { v: TimeAgoEnum.MONTH, t: 'Months', l: TimeLimitEnum.MONTH} ] idxParams = -1; createdAt! : *number*; diffTime! : *number*; shouldContinue = true; resultTimeAgo = ""; *constructor*(*createdAt*: *number*) { this.createdAt = createdAt; this.diffTime = Math.floor(Date.now() - createdAt); } next(): <u>StackNode</u> { if (this.shouldContinue == false) throw new Error('Cannot next') *const* currenParam = this.params\[this.idxParams]; *const* compare = Math.floor(this.diffTime / currenParam.v.valueOf()); if (compare <= 0 || compare < currenParam.l.valueOf()) this.shouldContinue = false; if (compare > 0) this.diffTime = compare; this.resultTimeAgo = `${this.diffTime} ${currenParam.t} ago!`.toLowerCase(); return this; } isNext(): <u>Boolean</u> { this.idxParams += 1; if (this.idxParams == this.params.length) return false; return this.shouldContinue; } get(): *string* { return this.resultTimeAgo; }} @Pipe({ name: 'timeAgo', standalone: true})export *class* <u>TimeAgoPipe</u> implements *<u>PipeTransform</u>* { transform(*value*: *string*, ...*args*: *string*\[]): *string* { console.log(`${value}`); *const* timeAgo = new TimeAgo(Number(value)) while (timeAgo.isNext()) timeAgo.next(); return timeAgo.get(); } }
Documentacion de pipes [Angular - Transforming Data Using Pipes](https://angular.io/guide/pipes)