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

Evitando memory leaks con ngDestroy

39/71
Recursos

¿Qué es ngOnDestroy y cómo prevenir fugas de memoria?

En el desarrollo de aplicaciones web, comprender cómo manejar correctamente el ciclo de vida de los componentes es crucial, especialmente cuando hablamos de prevenir fugas de memoria. En Angular, el método ngOnDestroy es nuestra ancla para abordar esto efectivamente. Este método se ejecuta cuando un componente se desmonta, liberando los recursos que el componente estaba utilizando. Vamos a desglosar este concepto con un ejemplo práctico y ver cómo evitar que ciertas tareas sigan consumiendo memoria innecesariamente.

¿Cómo implementar un contador reactivo con setInterval?

Para comprender mejor el papel de ngOnDestroy, primero configuraremos un contador simple que actualiza su valor cada segundo. Usaremos setInterval para incrementar este contador y ver cómo todo encaja en nuestro ciclo de vida del componente.

let counterRef: number | undefined;  // Variable para almacenar la referencia del intervalo

// Ejemplo de creación de un contador con setInterval
counterRef = window.setInterval(() => {
  this.counter.update(value => value + 1);  // Actualizamos el contador
}, 1000);

En este bloque de código, hemos creado un contador que se incrementa cada segundo utilizando setInterval. Esto es útil para entender cómo JavaScript maneja tareas en segundo plano.

¿Por qué setInterval sigue corriendo después de ngOnDestroy?

Un error común es asumir que al destruir un componente con ngOnDestroy, todas las funciones asociadas también se detienen automáticamente. Sin embargo, esto no ocurre de manera predeterminada. En el caso de setInterval, JavaScript seguirá ejecutándolo en el event loop, porque no se le ha dado una instrucción explícita de detención.

ngOnDestroy() {
  if (counterRef !== undefined) {
    window.clearInterval(counterRef);  // Detenemos el intervalo
  }
}

La clave aquí es usar window.clearInterval en ngOnDestroy para matar el intervalo. Al hacerlo, prevenimos que el proceso siga consumiendo recursos innecesarios del navegador, eliminando así cualquier riesgo de fugas de memoria.

¿Qué pasaría con otras tareas en segundo plano?

El principio aplicado a setInterval se extiende a otras ejecuciones en segundo plano, como WebSockets, Subscripciones a Streams de datos, y más. Si no las detienes adecuadamente, pueden continuar ejecutándose incluso después de que el componente haya sido destruido, resultando en un consumo innecesario de memoria y recursos.

Para cada tipo de tarea en segundo plano:

  • WebSockets: Cerrar el socket explícitamente en ngOnDestroy.
  • Subscripciones: Utilizar métodos de unsubscribe para cancelar subscripciones activas a data streams.
  • Promesas/Fetch: Manejar correctamente para evitar operaciones pendientes.

Al entender y aplicar estos principios, puedes crear aplicaciones web que no solo funcionan correctamente, sino que también gestionan recursos de manera eficiente, asegurando una experiencia de usuario más fluida y libre de problemas de memoria. La atención a estos detalles es lo que distingue a un desarrollador experto en Angular. ¡Continúa explorando y aprendiendo para convertirte en uno!

Aportes 13

Preguntas 0

Ordenar por:

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

Recomiendo usar RXJS con un interval: *interval$*: Subscription | null = null; ngOnInit(): void { this.interval$ = interval(1000).subscribe(() => { *console*.log(this.counter()); this.counter.update(*value* => *value* + 1); }); } ngOnDestroy(): void { this.interval$?.unsubscribe(); }
Para los que tienen el error de windows no definido les comento brevemente: Lo que sucede es que tu proyecto esta definido para ser una aplicación que se renderiza desde el servidor (SSR) y en el servidor el elemento windows no existe. Puedes quitar esta opción de tu proyecto eliminando angular universal o puedes indicarle al proyecto que si encuentra el comando windows no las ejecute hasta estar del lado del cliente. Te dejo los comandos que puedes agregar para lograr esto: 1. Agregar las siguientes dependencias: import { Component, signal, OnInit, OnDestroy, PLATFORM\_ID, Inject } from '@angular/core';import { CommonModule, isPlatformBrowser } from '@angular/common'; 1. Donde tengan el comando window debe estar dentro del siguiente if que lo que hace es preguntar estas del lado del cliente o del servidor. Si estas del lado del cliente ejecuta las lineas de adentro: ` if (isPlatformBrowser(this.platformId`)) { ` // write your client side code here` ` }` 1. En el proyecto se hace en el ngOnInit y en el ngOnDestroy por ejemplo para el OnInit ` ngOnInit(): void {    ` `if (isPlatformBrowser(this.platformId)) {      this.constContadorReference = window.setInterval(()=>{        this.contador.update(prevValiu => prevValiu +1 );        console.log("Contando")      }, 1000)    }  ` `}`
Me sale este bug ERROR ReferenceError: window is not defined

Bueno voy a hablar de lo mismo que los comentarios de abajo de como solucionar el error.

Descripcion

El codigo de angular se ejecuta solamente del lado del servidor SSR (Server Side Render) por las configuraciones que deberiamos tener en este momento.

Por lo cual no existen (window y document) hasta que pase la primera renderizacion por eso el codigo funciona aun con el mensaje de error en consola.

Solucion

Soluciones hay varias pero usar las herramientas que ofrece Angular es muy util esas son Inject, PLATFORM_ID from @angular/core y la validacion de isPlatformBrowser from @angular/common.

export class CounterComponent {
  @Input({required: true}) duration: number = 0; // usar el hardtypo no es obligatorio
  @Input({required: true}) message: string = '';
  counter =  signal(0);
  counterRef: number | undefined;
  constructor( @Inject(PLATFORM_ID) private plataformId: object){ // Never async
    console.log('construnctor');
    console.log('-'.repeat(10));
    // before show component  
  }
	  ngAfterViewInit(){
    // after render 
    // handle child changed
    console.log('ngAfterViewInit');
    console.log('-'.repeat(10));
    if (isPlatformBrowser(this.plataformId)) { // Esto se va a ejecutar solamente en el navegador
// podemos usar todo lo que queramos del DOM dentro del if 
      this.counterRef = window.setInterval(() => {
        console.log('run interval');
        this.counter.update(statePrev => statePrev + 1);
      },1000)
    }
  }
}

Esto es muy util si queremos asegurarnos de que ese bloque de codigo se va a ejecutar solamente en el navegador.
Creo que se podria hacer un decorador para que sea mas facil de implementar y menos repetitivo.

Nota: Ese ejercicio tambien lo podemos hacer con NgZone pero sin agregar los window. Feliz dia de estudio 😃

![]()![](https://static.platzi.com/media/user_upload/image-547043a0-e06c-4029-9136-7173eca6c404.jpg) para los que estuvieron teniendo esta advertencia me tomo un tiempo pero logre saber que era y una situación del ngZone hice esto en el constructor y lo implemente como una función antes del this.counterRef en el ngOnInt ![](https://static.platzi.com/media/user_upload/image-bc33f44d-1c7b-4173-934c-7d0e4233a953.jpg) ![](https://static.platzi.com/media/user_upload/image-78b03025-fa40-4837-b4d6-db82df6fb06a.jpg) Ya que la excluye fuera de la zona de Angular
Para el caso del error de windows no está definido, en mi caso lo solucione, agregando una if para el windows.clearInterval, es decir si counterRef tiene un valor (es decir, no es `null` o `undefined`), se llama a windows.clearInterval para destruir el objeto. ngOnDestroy() {    // before destroying the component    console.log('ngOnDestroy');    console.log('\_'.repeat(10));    console.log('valor de counterRef: ',this.counteRef);    if(this.counteRef) {     window.clearInterval(this.counteRef);    }  }
Solucion al error de window, en angular 19 Importar PLATFORM\_ID e Inject en angular core y isPlatformBrowser ```ts import { Component, Input, signal, SimpleChanges, PLATFORM_ID, Inject } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; ```en el constructor pasar este parametro ```ts constructor(@Inject(PLATFORM_ID) private platformId: Object){ // no async // before render // una vez console.log('constructor'); console.log('-'.repeat(10)); } ```y en los metodos de ngOnInit() y ngOnDestroy() agregar una validacion para detectar si el código está ejecutándose en el cliente o en el servidor ```ts ngOnInit(){ // after render // una vez // async, then, subs console.log('ngOnInit'); console.log('-'.repeat(10)); console.log('duration =>', this.duration); console.log('msg =>', this.msg); if (isPlatformBrowser(this.platformId)){ this.counterRef = window.setInterval(() => { console.log('run interval') this.counter.update(statePrev => statePrev + 1); }, 1000); } } ngOnDestroy(){ console.log('ngOnDestroy'); console.log('-'.repeat(10)); if (isPlatformBrowser(this.platformId)){ window.clearInterval(this.counterRef); } } ```
Hay un curso de angular como primeros pasos? :D es que siento que este curso es como para personas que ya han trabajdo con angular, si. entiendo la clase pero digamos que no como cuando ves el curso de react con Juan que es de 0 al nivel que quieras llegar... Igual bueno podria buscar documentacion ::)
Me sale este error acerca de do.Something :( TS2339: Property 'doSomething' does not exist on type 'CounterComponent'. \[plugin angular-compiler] src/app/domains/shared/components/counter/counter.component.ts:32:11: 32 │ this.doSomething();
Me sale el NG0505 y no encontré una solución, vi los que pusieron mas abajo, pero no me resulto, para empezar yo tengo "@angular-devkit/build-angular:application" y no browser y la segunda donde tengo que cambiar los booleanos en development tampoco resulto :(
a mi me dio error cuando hice el this.counter = window.setInterval(() ![](https://static.platzi.com/media/user_upload/image-5b5f092d-8f33-49ab-abd6-f4a23f915c22.jpg) El tipo 'number' no se puede asignar al tipo 'WritableSignal\<number>'.ts(2322) (property) CounterComponent.counter: WritableSignal\<number>
Interesante!