Comienza a usar los indicadores de Angular

1. Antes de comenzar

Logotipo de Angular negro

Los indicadores de Angular presentan tres primitivas reactivas al Angular que conoces y amas, lo que simplifica tu desarrollo y te ayuda a compilar apps más rápidas de forma predeterminada.

Qué compilarás

  • Aprenderás sobre las tres primitivas reactivas que se introdujeron con los indicadores de Angular: signal(), computed() y effect().
  • Usa los indicadores de Angular para potenciar un juego de cifrado de Angular. Los algoritmos de cifrado son sistemas para encriptar y desencriptar datos. En este juego, los usuarios pueden decodificar un mensaje secreto arrastrando y soltando pistas para resolver un algoritmo de cifrado, personalizar el mensaje y compartir la URL a fin de enviar mensajes secretos a los amigos.

Juego de Chip Cypher al estilo de una consola de juegos verde vintage, con un mensaje oculto en la pantalla "Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!"

Requisitos previos

  • Conocimientos de Angular y TypeScript
  • Recomendado: Mira el video Rethinking Reactivity with Signals para obtener más información sobre la biblioteca de Angular Signals

2. Obtén el código

Todo lo que necesitas para este proyecto está en Stackblitz. Stackblitz es el método recomendado para trabajar en este codelab. Como alternativa, clona el código y ábrelo en tu entorno de desarrollo favorito.

Abre Stackblitz y ejecuta la app.

Para comenzar, abre el vínculo de Stackblitz en tu navegador web favorito:

  1. Abra una nueva pestaña del navegador y vaya a https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcrypt%2Fservice.crypt.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
  2. Bifurca Stackblitz para crear tu propio lugar de trabajo editable. Stackblitz debería ejecutar automáticamente la app, y ¡listo!

Alternativa: Clona el repositorio y entrega la app

El uso de VSCode o un IDE local es un método alternativo para trabajar en este codelab:

  1. Abre una nueva pestaña del navegador y ve a https://github.com/angular/codelabs/tree/signals-get-started.
  2. Bifurca y clona el repositorio, y usa el comando cd codelabs/ para moverte al repositorio.
  3. Revisa la rama de código de inicio con el comando git checkout signals-get-started.
  4. Abre el código en VSCode o en el IDE que prefieras.
  5. A fin de instalar las dependencias necesarias para ejecutar el servidor, usa el comando npm install.
  6. Para ejecutar el servidor, usa el comando ng serve.
  7. Abre una pestaña del navegador en http://localhost:4200.

3. Cómo establecer un modelo de referencia

El punto de partida es un juego de cifrado de Angular, pero aún no funciona. Los indicadores de Angular potenciarán la funcionalidad del juego.

Juego de Chip Cypher al estilo de una consola de juegos verde vintage, con un mensaje oculto en la pantalla "Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!"

Para comenzar, repasa la versión terminada de lo que compilarás: Cypher de los indicadores de Angular.

  1. Visualiza el mensaje codificado en la pantalla.
  2. Arrastra y suelta un botón de letra en el teclado para resolver el cifrado y decodificar el mensaje secreto.
  3. Si se realiza de forma correcta, observa cómo se actualiza el mensaje para decodificar más mensajes secretos.
  4. Haz clic en Personalizar para cambiar el Remitente y el Mensaje y, luego, en Crear y copiar URL para ver los valores en la pantalla y la URL cambia.
  5. Bonificación: Copia y pega la URL en una pestaña nueva o compártela con un amigo, y mira cómo se almacenan el remitente y el mensaje en la URL.

GIF del juego de Angular Cypher, con un mensaje oculto que se decodifica en la pantalla para deletrear “Angular Signals are in developer preview in v16 today!”

4. Define tu primer indicador()

Un indicador es un valor que puede indicarle a Angular cuándo cambia. Algunos indicadores se pueden cambiar directamente, mientras que otros calculan sus valores a partir de los valores de otros. En conjunto, los indicadores crean un grafo dirigido de dependencias que modela el flujo de datos en tu app.

Angular puede usar las notificaciones de los indicadores para saber qué componentes deben detectarse ante un cambio o ejecutar las funciones de efecto que usted defina.

Convierte superSecretMessage en signal()

superSecretMessage es un valor en MessageService que define el mensaje secreto que decodifica el jugador. Actualmente, el valor no notifica a la app sobre los cambios, por lo que no funciona el botón Customize. Puedes resolverlo con una señal.

Si haces que superSecretMessage sea un indicador, podrás notificar a las partes de la app que dependan de saber cuándo cambió el mensaje. Cuando personalices el mensaje en un diálogo, establecerás el indicador para actualizar el resto de la app con el mensaje nuevo.

Para definir tu primer indicador, sigue estos pasos en el comentario TODO(1): Define your first signal() de cada archivo:

  1. En el archivo service.message.ts, usa la biblioteca de indicadores para hacer que superSecretMessage sea reactivo:

src/app/secret-message/service.message.ts

superSecretMessage = signal(
  'Angular Signals are in developer preview in v16 today!'
);

Se te pedirá automáticamente que importes signal desde @angular/core. Si actualizas la página, es probable que encuentres errores donde hace referencia a superSecretMessage. Esto se debe a que cambiaste el tipo de superSecretMessage de string a SettableSignal<string>. Para solucionar este problema, cambia todas las referencias de superSecretMessage a fin de usar la API de Signals. Cuando leas el valor, llama al método get superSecretMessage(). Y donde escribas el valor, usa la API de .set en SettableSignal para configurar el valor nuevo del mensaje.

  1. En los archivos secret-message.ts y service.message.ts, actualiza todas las referencias de superSecretMessage a superSecretMessage():

src/app/secret-message/secret-message.ts.

// Before
this.messages.superSecretMessage
this.messages.superSecretMessage = message;

// After
this.messages.superSecretMessage()
this.messages.superSecretMessage.set(message);

src/app/secret-message/service.message.ts.

// Before
this.superSecretMessage

// After
this.superSecretMessage()

Explore los otros dos indicadores

  • Observa que tienes otros dos indicadores en tu app:

src/app/crypt/service.crypt.ts.

cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);

El CipherService define una señal cipher, una asignación generada de forma aleatoria de pares clave-valor de una letra del alfabeto a una nueva letra cipher. Se usa para desordenar el mensaje y determinar si el jugador encuentra una coincidencia exitosa en el teclado.

También tienes una señal decodedCipher de los pares clave-valor decodificados con éxito que agregarás a medida que el jugador resuelve el algoritmo de cifrado.

Un atributo potente y único del diseño de la biblioteca de indicadores de Angular es que puedes incorporar la reactividad en todas partes. Definiste indicadores una vez en los servicios de la app y puedes usarlos en una plantilla, componentes, canalizaciones, otros servicios o cualquier lugar donde puedas escribir código de aplicación. No están limitados al alcance del componente o no están vinculados a él.

Verifica los cambios

  • Debes realizar un paso más para que la app funcione. Por ahora, intenta agregar un elemento console.log() en diferentes partes de tu app para ver cómo se configura tu nuevo superSecretMessage.

Stackblitz con un mensaje de console.log() en el que se muestra que SuperSecretMessage registra correctamente el mensaje nuevo

5. Define tu primer compute()

En muchas situaciones, puede que derive el estado de valores existentes. Es mejor tener la actualización del estado derivado cuando cambia el valor dependiente.

Con computed(), puedes expresar de forma declarativa un indicador que derive su valor de otros indicadores.

Convierte solvedMessage en computed()

solvedMessage traduce el valor secretMessage de codificado a decodificado con la señal decodedCipher.

Esto es extraordinario porque puede ver que deriva un cálculo basado en otro, por lo que cada vez que cambia una señal dentro de ese contexto reactivo asignado, se notifican las dependencias.

Actualmente, solvedMessage no se actualiza cuando cambias secretMessage, decodedCipher o superSecretMessage. Por lo tanto, no ves actualizaciones en la pantalla cuando el reproductor resuelve el cifrado.

Si haces que solvedMessage se calcule, crearás un contexto reactivo para que, cuando actualices el mensaje o resuelvas el algoritmo de cifrado, puedas obtener la actualización de estado de las dependencias con seguimiento.

Para convertir solvedMessage en computed(), sigue estos pasos en el comentario TODO(2): Define your first computed() de cada archivo:

  1. En el archivo service.message.ts, usa la biblioteca de indicadores para hacer que solvedMessage sea reactivo:

src/app/secret-message/service.message.ts.

solvedMessage = computed(() =>
  this.translateMessage(
    this.secretMessage(),
    this.cipher.decodedCipher()
  )
);

Se te pedirá automáticamente que importes computed desde @angular/core. Si actualizas la página, es probable que encuentres errores donde hace referencia a solvedMessage. Esto se debe a que cambiaste el tipo de superSecretMessage de string a Signal<string>, una función. Para solucionar este problema, cambia todas las referencias de solvedMessage a solvedMessage().

  1. En el archivo secret-message.ts, actualiza todas las referencias de solvedMessage a solvedMessage():

src/app/secret-message/secret-message.ts.

// Before
<span *ngFor="let char of this.messages.solvedMessage.split(''); index as i;" [class.unsolved]="this.messages.solvedMessage[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

// After
<span *ngFor="let char of this.messages.solvedMessage().split(''); index as i;" [class.unsolved]="this.messages.solvedMessage()[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

Ten en cuenta que, a diferencia de superSecretMessage, solvedMessage no es SettableSignal, no puedes cambiar su valor directamente. En su lugar, su valor se mantiene actualizado cuando se actualiza cualquiera de sus indicadores de dependencia (secretMessage y decodedCipher).

Explora las otras dos funciones computed()

  • Observa que tienes otros dos valores calculados en tu app:

src/app/secret-message/service.message.ts.

secretMessage = computed(() =>
  this.translateMessage(
    this.superSecretMessage(),
    this.cipher.cipher()
  )
);

src/app/crypt/service.crypt.ts.

unsolvedAlphabet = computed(() =>
  ALPHABET.filter(
    (letter) => !this.decodedCipher().find((guess) => guess.value === letter)
  )
);

MessageService define un secretMessage calculado, el superSecretMessage codificado por el cipher que los jugadores deben resolver.

CipherService define un unsolvedAlphabet calculado, una lista de todas las letras que el jugador no resolvió, que deriva de la lista de claves de cifrado resueltas en decodedCipher.

Verifica los cambios

Ahora que superSecretMessage es un indicador y solvedMessage es un cálculo, la app debería funcionar. Prueba las funciones del juego:

  1. Arrastra y suelta una LetterGuessComponent en una LetterKeyComponent en tu CipherComponent para resolver el cifrado y decodificar el mensaje secreto.
  2. Observa cómo se actualiza SecretMessageComponent a medida que decodificas más mensajes secretos.
  3. Haz clic en Personalizar para cambiar el Remitente y el Mensaje y, luego, en Crear y copiar URL para ver los valores en la pantalla y la URL cambia.
  4. Bonificación: Copia y pega la URL en una pestaña nueva o compártela con un amigo, y mira cómo se almacenan el remitente y el mensaje en la URL.

GIF del juego de Angular Cypher, con un mensaje oculto que se decodifica en la pantalla para deletrear “Angular Signals are in developer preview in v16 today!”

6. Agrega tu primer efecto()

En algunas ocasiones, es posible que quiera que ocurra algo cuando un indicador tiene un valor nuevo. Con effect(), puedes programar y ejecutar una función de controlador en respuesta a los cambios de indicadores.

Agrega confeti cuando se resuelve el algoritmo de cifrado

Ahora que la app es funcional, puedes agregar confeti cuando el código de cifrado se resuelva y el mensaje secreto se decodifique.

Para agregar confeti, sigue estos pasos en el comentario TODO(3): Add your first effect():

  1. En el archivo cipher.ts, programa un efecto para agregar confeti cuando se decodifique el mensaje:

src/app/crypt/crypt.ts

import * as confetti from 'canvas-confetti';

ngOnInit(): void {
  ...

  effect(() => {
    if (this.messages.superSecretMessage() === this.messages.solvedMessage()) {
      var confettiCanvas = document.getElementById('confetti-canvas');
      confetti.create()(confettiCanvas, { particleCount: 100 });
    }
  });
}

Observa que este efecto depende de una señal y un valor calculado: this.messages.superSecretMessage() y this.messages.solvedMessage().

Effect te ayuda a programar la función de confeti en un contexto reactivo para hacer un seguimiento y volver a evaluar cuando se actualizan sus dependencias.

Verifica los cambios

  • Intenta resolver el algoritmo de cifrado (pista: puedes cambiar el mensaje a algo corto para probarlo más rápido). Un confeti pop te felicitará por tu primer effect().

GIF del juego de Cypher de Angular, con un mensaje oculto decodificado en la pantalla para deletrear "Hora de confeti" y confeti que suena cuando se resuelve el mensaje.

7. Felicitaciones

Tu algoritmo de cifrado de Angular ya está listo para decodificar y compartir mensajes secretos. ¿Tienes un mensaje para el equipo de Angular? Etiqueta nuestras redes sociales en @Angular para que podamos decodificarlo. 🎉

El juego de Angular Cypher se resolvió con un mensaje oculto en la pantalla que indica que Angular Signals está en la vista previa para desarrolladores en la versión 16 hoy.

Ahora tienes tres primitivas reactivas nuevas en tu caja de herramientas de Angular para simplificar tu desarrollo y compilar apps más rápidas de forma predeterminada.

Más información

Consulta estos codelabs:

Lee los siguientes materiales: