Sabemos como crear Componentes en Angular, pero ¿cómo se conectan componentes entre sí?

Una de las ventajas de los componentes web es que puedes crearlos pensando en que puedes usarlos en varios sitios, para ello puedes requerir que cada uno se pueda "personalizar". Por ejemplo, imagina que creas un componente para pintar un botón. Si a ese botón le pones un texto, en cualquier sitio donde uses ese componente va a mostrar el mismo texto, ¿no sería genial poder cambiar el texto dependiendo del texto que necesitemos en ese momento?

El ejemplo anterior es un ejemplo de comunicación desde el padre al hijo, pero también se puede hacer al revés, por ejemplo, para hacer una acción en el componente padre cuando ocurra algo en el hijo como pulsar un botón por ejemplo.

Dentro de la comunicación entre componentes en Angular, hay varios tipos dependiendo de lo que necesitemos. A continuación vamos a verlos:

Comunicación entre componentes en Angular

Comunicación desde el componente padre al hijo mediante input

Consiste en usar la etiqueta @Input de Angular. Ésta etiqueta se pone en el componente hijo para indicar que esa variable proviene desde fuera del componente, es decir desde el componente padre.

A esto se en otros frameworks como Vue se le suele llamar props. Con esto vas a poder tener un componente que sea configurable pudiendo pasar datos al usarlo.

Veamos un ejemplo, en el componente hijo:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
      Message from parent: {{childMessage}}
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  @Input() childMessage: string;

  constructor() { }

En el componente padre:

import { Component } from "@angular/core";

@Component({
  selector: "app-parent",
  template: ` <app-child [childMessage]="parentMessage"></app-child> `,
  styleUrls: ["./parent.component.css"],
})
export class ParentComponent {
  parentMessage = "message from parent";
  constructor() {}
}

Para el ejemplo he puesto el template html de los componentes directamente en el controlador para ahorrar espacio pero funciona igual si tienes un archivo html a parte. El valor de la variable childMessage viene desde el componente padre y se la pasamos desde el html mediante [childMessage].

Comunicación desde el componente hijo al padre mediante ViewChild()

Mediante ViewChild, el padre crea el componente hijo y tiene acceso a sus datos y atributos:

En el hijo:

import { Component } from "@angular/core";

@Component({
  selector: "app-child",
  template: ``,
  styleUrls: ["./child.component.css"],
})
export class ChildComponent {
  message: string = "Hola Mundo!";

  constructor() {}
}

En el padre:

import { Component, ViewChild, AfterViewInit } from "@angular/core";
import { ChildComponent } from "../child/child.component";

@Component({
  selector: "app-parent",
  template: `
    Message: {{ message }}
    <app-child></app-child>
  `,
  styleUrls: ["./parent.component.css"],
})
export class ParentComponent implements AfterViewInit {
  @ViewChild(ChildComponent) child;

  constructor() {}

  message: string;

  ngAfterViewInit() {
    this.message = this.child.message;
  }
}

La particularidad de éste método es que tenemos que esperar a que la vista esté totalmente cargada para acceder a los atributos del hijo. Para ello creamos un método de Angular llamado ngAfterViewInit() en el que simplemente inicializamos la variable con el valor del atributo del hijo (el hijo lo declaramos como @ViewChild(ChildComponent)).

Comunicación desde el componente padre al hijo mediante output y eventos

Éste método es útil cuando queremos queremos informar de cambios en los datos desde el hijo, por ejemplo, si tenemos un botón en el componente hijo y queremos actualizar los datos del padre.

En el hijo:

import { Component, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-child",
  template: ` <button (click)="sendMessage()">Send Message</button> `,
  styleUrls: ["./child.component.css"],
})
export class ChildComponent {
  message: string = "Hola Mundo!";

  @Output() messageEvent = new EventEmitter<string>();

  constructor() {}

  sendMessage() {
    this.messageEvent.emit(this.message);
  }
}

En el padre:

import { Component } from "@angular/core";

@Component({
  selector: "app-parent",
  template: `
    Message: {{ message }}
    <app-child (messageEvent)="receiveMessage($event)"></app-child>
  `,
  styleUrls: ["./parent.component.css"],
})
export class ParentComponent {
  constructor() {}

  message: string;

  receiveMessage($event) {
    this.message = $event;
  }
}

En el hijo declaramos un evento de tipo EventEmitter y con la pulsación del botón ejecutamos un método para lanzar el evento al padre. Desde el padre creamos una función para recibir el mensaje desde el evento y incluimos en la etiqueta del html (messageEvent)="receiveMessage($event) para conectar el evento al método que hemos creado.

Compartir datos usando servicios

Ota forma de pasar información entre componentes es mediante el uso de los Servicios en Angular, encargados de la adquisición de datos para los componentes.

Una estrategia sería meter en un servicio una forma de guardar datos, ya sea en localStorage, cookies, base de datos en memoria, etc.

Para cosas simples te puede valer, pero para casos algo más complejos te recomiendo mejor usar un sistema de store, el de Angular se llama ngrx.