Comunicación entre componentes no relacionados en Angular

Daniel Barrientos
7 min readJun 5, 2020

--

Vamos a profundizar en cómo funciona la comunicación en componentes no relacionados

En angular los componentes se pueden comunicar por las siguientes formas:

  1. De componente Padre a componente Hijo usando Input():

2. De componente Hijo a componente Padre usando Output() y EventEmmitter:

3. De componente Hijo a componente Padre usando ViewChild.

4. De Componente a componente sin relación.

En este artículo nos concentraremos en la opción 4

Problema a resolver

Tenemos n cantidad de componentes no relacionados y necesitamos que se comuniquen, por este motivo la solución 1, 2, 3 no son convenientes para solucionar este problema. Por otra parte, necesitamos enviar o emitir datos no importando en qué ciclo de vida este el componente.

Dividamos el problema en los siguientes puntos:

  1. Necesitamos una forma en la que podamos pasar datos sin necesidad de que los componentes estén relacionados ( pueden ser 2 o más componentes).
  2. Necesitamos que cualquiera de estos componentes pueda recibir o modificar dichos datos.
  3. Necesitamos persistencia de datos entre componentes( que cada uno posea el mismo valor).
  4. Necesitamos integridad de datos (evitar que se ingresen valores inválidos).
  5. Necesitamos que todos los componentes sepan cuando cambia el valor.

Nota: Cuando se crean componentes en angular no deberían ser dependientes de otros. Se deberían crear con una responsabilidad única y que ellos sean los administren lo que hacen.

Solución

Para lograr lograr la comunicación entre componentes no relacionados haremos uso de un “Servicio” de angular y un Subject o Behavior Subject de las libreria RxJs.

Service

Para empezar, la documentación oficial de un servicio está aquí. Lo más importante que tenemos que saber de un servicio es que es un objeto/clase que aplica el patrón Singleton.

Con un servicio podemos centralizar los datos, asignando la responsabilidad del manejo de la información a dicho servicio y a su vez podemos realizar las validaciones correspondientes. Con esto abarcaremos los puntos 1, 2, 3, 4.

Para usar un servicio en angular lo que necesitamos es inyectarlo en el constructor, para esto es importante entender Inyección de dependencias.

El primer componente que inyecte el servicio en el constructor será el que cree una instancia del servicio. Los demás componentes que inyecten dicho servicio obtendrán una copia de la instancia. Por ende, podrán ver los mismos datos no importando quien lo invoque.

Datos

Ahora que tenemos cubiertos los puntos del 1 al 4, nos queda pendiente el punto 5. Para lograrlo agregaremos los atributos, que los componentes tendrán en común, en el servicio.

Dichos atributos serán de tipo observable, para que cualquier componente que quiera estar al tanto de los respectivos cambios lo haga en tiempo real.

Para esto usaremos la librería RxJs. Esta librería nos brinda unos objetos que administran el observable, para que toda la responsabilidad de emitir y actualizar los datos sea centralizada en él.

Acá tenemos 2 opciones similares, pero para propósitos diferentes:

  1. Subject: esta opción la utilizaremos cuando no necesitamos que haya un valor inicial. Por otra parte, no necesitamos saber el valor anterior a ser instanciado el servicio. Normalmente, con este tipo de dato no nos importa el valor anterior o actual, solo el siguiente que se emitirá.
  2. Behavior Subject: Esta opción la utilizaremos cuando necesitamos que haya un valor por defecto o inicial. Por ello, cuando lo instanciamos necesitaremos definir un valor.

Las dos opciones ofrecen el mismo comportamiento para nuestra solución, sin embargo, cada una es para situaciones diferentes.

Nota: Es importante mencionar que cualquiera de los dos que elijamos, dicho atributo deberá ir privado. Esto con el fin de mantener la integridad de los datos, ya podemos validar internamente si los datos que estamos recibiendo son válidos.

Recomendaciones

Cuando escribimos código lo hacemos para que funcione y lo haga de la manera más optima. Sin embargo, también lo hacemos pensando en que otro desarrollador leerá nuestro código.

Teniendo esto en mente:

  1. Hay que tener cuidado en que carpeta colocamos nuestros servicios compartidos. Esto es importante porque al ser servicios que administran ellos mismos los datos no deberían estar en una carpeta de un componente especifico. Lo aconsejable es crear una carpeta de “Shared” y dentro de ellos una carpeta de “Communication Services”.
  2. Siempre asignar nombres descriptivos a los métodos y atributos. Ya que como van a ser utilizados en N cantidad de componentes.
  3. Que los servicios de comunicación sean los únicos que administran los datos. Si se declaran variables internas para almacenar los valores de los servicios, va a llegar un punto donde puede perderse la persistencia de datos porque algunos componentes tendrán valores distintos.

Ejemplo práctico

Para este ejercicio vamos a hacer lo siguiente:

A. Vamos a crear 2 componentes no relacionados y vamos a comunicarlos por medio de un servicio.

B. Vamos a enviar entre los componentes un atributo llamado “Edad” para probar el comportamiento de un Behavior Subject.

C. Vamos a a enviar entre los componentes un atributo llamado “Nombre” para probar el comportamiento de un Subject.

D. El valor podra ser enviado desde un input externo o desde cada componente.

Iniciemos!

  1. Creamos una nueva solución en angular:

ng new communications-components

2. Agregamos el framework de css bulma.io

npm install bulma

3. Agregamos la librería al archivo angular.json:

3. Generamos nuestro servicio:

ng g s shared/basic-info

4. Creamos dos componentes:

ng g c components/compA

ng g c components/compB

Trabajemos con el servicio

5. Agregamos en el servicio los atributos de messageA y messageB con su respectivo administrador:

El motivo por el que no creamos una propiedad nombre y sólo su administrador es porque no nos interesa almacenar el valor.

5. Agregamos los métodos accesores:

Trabajemos con el componente general

7. Agregamos estos estilos en el archivo de styles.css:

8. Eliminamos todo el contenido por defecto de app.component.html y lo reemplazamos por el nuestro:

Trabajemos con el componente A

9. Agregamos nuestra lógica al archivo de comp-a.component.ts:

10. Eliminamos todo el contenido por defecto de comp-a.component.html y lo reemplazamos por el nuestro:

11. Agregamos los estilos a nuestro comp-a.component.css:

Trabajemos con el componente B

12. Agregamos nuestra lógica al archivo de comp-b.component.ts:

13. Eliminamos todo el contenido por defecto de comp-b.component.html y lo reemplazamos por el nuestro:

14. Agregamos los estilos a nuestro comp-a.component.css:

Resultado final

Flujo del mensaje con Subject

Flujo del mensaje con Behavior Subject

Conclusión

Esta es una posible solución al problema de la comunicación entre componentes y no significa que los servicios sean mejores que las otras comunicaciones que mencionamos al principio. Simplemente es una solución a un problema especifico en un contexto dado.

De hecho, hay que ser muy cuidadosos con esta solución ya que si no organizamos bien dichos servicios, cuando nosotros u otros desarrolladores necesiten debugger el código les será muy complicado entender el flujo. Por ello, es importante comentar correctamente el código, seguir las recomendaciones anteriores y aplicar las mejores prácticas.

Para finalizar, nosotros escribimos código no solo para que funcione, sino que otros desarrolladores puedan leer nuestro código y “NO mueran en el intento”.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Daniel Barrientos
Daniel Barrientos

Written by Daniel Barrientos

I'm Principal frontend engineer, Follow me to learn together about web development, UI / UX, and problem solving.

Responses (1)

Write a response