¿De qué va esto?
Para practicar un poco el uso de los componentes en Angular, así como el data binding, vamos a crear un pequeño juego. Si necesitas reforzar tus conocimientos sobre esto temas, puedes consultar esta serie de posts, o esta guía para empezar con Angular si partes desde 0.
Instrucciones
1. crear 3 componentes: GameControl, Odd y Even.
2. el GameControlComponent debe tener 2 botones: uno para empezar el juego y otro para pausarlo.
3. al pulsar el botón de empezar el juego, emitir un evento cada 1 segundo
pista: evento con un número que vaya incrementando
4. guardar una referencia a este contador en alguna propiedad en GameControlComponent para poder cancelarlo en el futuro.
5. el evento emitido tiene que ser accesible (en inglés, listenable) desde fuera de su componente. Tiene que poder ser usado desde el AppComponent, desde donde deberemos usar el GameControlComponent.
6. al hacer click en el botón para pausar el juego, el contador debe pararse (con clearInterval, por ejemplo).
7. añadir un nuevo OddComponent cada vez que el evento creado por el GameControlComponent emita un número impar. Lo mismo para el EvenComponent, pero con números pares.
8. añadir al OddComponent y al EvenComponent diferentes estilos (colores, tamaño, etc).
Paso 1: Inicio y creación de los componentes de nuestra app
2. Creamos nuestros 3 componentes usando Angular CLI:
ng g c game-control --skipTests
Y lo mismo para los otros dos.
3. Añadimos Bootstrap para que nuestra app no se vea sumamente horrible.
Paso 2: Creación y ubicación de los botones
1. Vamos a crearnos los botones en el template del GameControlComponent.
2. Y a añadirlos al AppComponent template usando el selector del GameControlComponent. Borra primero todo el contenido por defecto con el que viene Angular.

Paso 3: Creación y emisión de un custom event
Aquí un esquemita para ubicar nuestro custom event y entender la estructura que queremos construir:

1. Añadimos un click event al botón "Start game" en el template del GameControlComponent y lo vinculamos a una función que posteriormente crearemos.
2. Nos creamos la función en el código TypeScript (en adelante, TS) del GameControlComponent. Dentro de esta función es donde colocamos el setInterval, una built-in function de JavaScript (en adelante, JS). Creamos también una propiedad (llamada interval) para poder acceder a la función y manipular el setInterval.
A nuestra propiedad le asignamos el valor del setInterval dentro de la función startGame.
3. Definimos el contenido de la función setInterval. La ejecutaremos cada 1 segundo y dentro contendrá nuestro custom event que posteriormente emitiremos. Para eso, definimos otra propiedad (llamada gameStarted, por ejemplo) y le asignamos el valor de new EventEmitter.
Nuestro EventEmitter será de tipo number.
4. Con esto ya podemos volver a nuestro setInterval y emitir nuestro evento. Como lo que queremos emitir es un número creciente (0, 1, 2, etc), declaramos una propiedad llamada incrementingNum, por ejemplo, y le damos el valor de 0, para que empiece a contar desde 0.
Al emitir el evento, le pasamos el valor de nuestro incrementingNum, incrementando en +1 a cada segundo. Hacemos un console.log para comprobar que efectivamente estamos emitiendo un número creciente cada 1 segundo.
5. Añadimos el decorador @Output() a nuestra propiedad gameStarted. Con esta adición ya podemos usar nuestro custom event en otro componente, como el AppComponent.
incrementingNum = 0; // starting value
@Output() gameStarted = new EventEmitter<number>();
constructor() { }
startGame() {
this.interval = setInterval(() => {
this.gameStarted.emit(this.incrementingNum++);
console.log(this.incrementingNum);
}, 1000);
}
Paso 4: Escuchando nuestro evento desde fuera de su componente
1. Dentro del AppComponent, añadimos el evento mediante event binding al selector <app-game-control> y lo vinculamos a un evento que posteriormente nos crearemos (onStartCounter, por ejemplo). Queremos capturar cierta información cuando nuestro evento se dispare, por lo que usamos el parámetro $event.
2. Configuramos el método onStartCounter en el archivo app.component.ts. De momento sólo vamos a hacer un console.log para ver el último número emitido. Sabemos que la función recibirá un número, así que lo indicamos en el parámetro.
onStartCounter(incrementingNum: number) { console.log(incrementingNum); }
Paso 5: Pausando el juego
1. Añadimos un click event a nuestro botón del archivo game-control.component.html (al de parar el juego) y lo vinculamos a un método que crearemos posteriormente (pauseGame, para ser consistentes con respecto al otro botón).
2. Vamos al archivo game-control.component.ts, donde configuraremos nuestro método pauseGame. Para conseguir que nuestro setInterval deje de emitir eventos (números), simplemente tenemos que llamar a otra built-in function de JS: clearInterval.
A esta función le pasamos nuestra propiedad interval porque es la que hemos establecido como referencia a la función setInterval.
pauseGame() { clearInterval(this.interval); }
¡Y listo! Ve a tu navegador y comprueba en las dev tools cómo dejan de emitirse números al pulsar el botón de "stop".
Paso 6: Mostrar un componente u otro (EvenComponent o OddComponent) según la naturaleza del número (par o impar)
1. Vamos al archivo odd.component.html y nos creamos un párrafo donde mostraremos nuestros números impares mediante string interpolation. La propiedad que le pasamos (llamada oddNumber, por ejemplo), la configuraremos a continuación.
2. Configuramos nuestra propiedad oddNumber en el archivo odd.component.ts. Como vamos a pasar el valor de oddNumber desde fuera del componente (desde el AppComponent), le añadimos el decorador @Input.
@Input() oddNumber: number;
3. En el archivo app.component.html, inyectamos el OddComponent mediante su selector de HTML. Nuestra intención es generar un componente como este cada vez que se emita un número impar, así que este parece el caso ideal para añadirle un ngFor.
Pero tenemos un problemilla: no tenemos ningún array para poder utilizarlo con el ngFor. Así que tendremos que crearlo. Si observamos el archivo app.component.ts, vemos que ahora estamos imprimiendo todo número, sea impar o impar. Vamos a cambiar eso.
4. Nos creamos dos arrays vacíos (oddNumbers y evenNumbers). Ahora, dentro de la función onStartCounter comprobamos si el número que se emite es par o impar. Para eso podemos usar el modulus operator (%). El modulus operator funciona de la siguiente manera:
Si un número X es divisible por 2, significa que el número es par. Esto en código se traduce como:
myNumber % 2 === 0
Todo esto lo hacemos en un bloque de if else, añadiendo el incrementingNumber (push) al array de evenNumbers si resulta ser par, y al otro array en caso contrario.
oddNumbers = []; evenNumbers = []; onStartCounter(incrementingNum: number) { if(incrementingNum % 2 === 0) { // if it's even this.evenNumbers.push(incrementingNum); } else { // if it's odd this.oddNumbers.push(incrementingNum); } }
5. Ahora ya podemos volver al archivo app.component.html y completar nuestro ngFor. Además, para poder mostrar los números impares en el navegador, debemos vincular nuestra propiedad oddNumber (del OddComponent, recuerda) mediante property binding y asignarle el valor de nuestra variable local (la que tendremos que declarar en el ngFor).
Y...¡tadáááá!
6. Vamos a replicar la misma configuración hecha en el OddComponent sobre el EvenComponent:
@Input() evenNumber: number;
Y con esta configuración ya deberías ver que en tu navegador se muestran tanto números pares como impares
Aunque como habrás observado, los números impares se muestran primero y los pares, después. Esto es debido a cómo hemos posicionado nuestros componentes en el AppComponent, ya que hemos puesto uno debajo del otro:
Paso 7: Dando distintos estilos a nuestros componentes
Angular utiliza un sistema de styles encapsulation para definir los estilos de un componente (puedes ver los detalles en este post). Así que sencillamente tenemos que usar el archivo CSS de cada componente para darle el estilo que queramos a nuestros párrafos.
Por ejemplo, en el archivo odd.component.css podríamos escribir:
Y en el archivo even.component.css:
Y, gracias a la magia del styles encapsulation, cada archivo CSS se aplicará sólo a los elementos de su componente. Con esto, deberías ver en tu navegador cómo los números pares e impares se muestran con un color distinto.
Existe otra manera de aplicarle estilos a nuestro código, y es usando la directiva ngStyle. De esta manera no tenemos que tocar los archivos CSS, porque utilizamos la directiva directamente en la template.
1. Aplicamos la directiva al even.component.html con el estilo que queramos darle, por ejemplo:
2. Hacemos lo mismo en el odd.component.html:
¡Y voilà!

¡RETO CONSEGUIDO!
¡Y hasta aquí este ejercicio! Si te queda alguna duda, ¡nos vemos en los comentarios! Si crees que este post puede serle útil a alguien, ¡compártelo! Y si de verdad quieres ayudarme, cómprate algo en Amazon usando este link. Yo me llevaré una pequeña comisión y a ti no costará nada extra.
Otros artículos que pueden interesarte
Hola Lilia.
Efectivamente, teníamos un console.log en el game-control.component.ts, así que para no ver los números repetidos, puedes comentarlo (añadiendo // delante).
Hola! Tengo una pregunta sobre el paso 3 y paso 4. Si se llevan a cabo ambos, nos dan el resultado duplicado en la consola. Entiendo que son dos formas diferentes de hacerlo, no? Dado que si se omite el paso 4, sigo obteniendo el mismo resultado sin el número duplicado. En caso de que sea necesario el paso 4, que tengo que hacer para que el resultado no me aparezca repetido?
Gracias