Make writing a habit together! This is the 8th day of my participation in the “Gold Digging Day New Plan Β· April More Text Challenge”. Click here for more details

Last time, we talked about Angular with NG-Zorro rapid development. Front-end development, to a large extent, is componentized development, which is inseparable from the communication between components. What about communication between Angular components in Angular development?

Vue and React are similar

This article is pure text, more boring. Because the console print things are relatively weak, so it does not fit the graph, HMM ~ hope readers follow the instructions to walk through the code easier to absorb ~

1. The parent component passes values to the child components via properties

You define a property and pass the value to the child component through the introduction of the component. Show you the CODE.

<! -- parent.component.html -->

<app-child [parentProp] ="'My kid.'"></app-child>
Copy the code

Calls the child component in the parent component, naming a parentProp property here.

// child.component.ts

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

@Component({
  selector: 'app-child'.templateUrl: './child.component.html'.styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {
  // Enter the decorator
  @Input() parentProp! :string;

  constructor() { }

  ngOnInit(): void{}}Copy the code

The child component takes the variable parentProp passed in by the parent and fills it back into the page.

<! -- child.component.html -->

<h1>Hello! {{ parentProp }}</h1>
Copy the code

2. Child components transmit information to their parents through Emitter events

Passing data from the child to the parent via new EventEmitter().

// child.component.ts

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

@Component({
  selector: 'app-child'.templateUrl: './child.component.html'.styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {
  // Output decorator
  @Output(a)private childSayHi = new EventEmitter()

  constructor() { }

  ngOnInit(): void {
    this.childSayHi.emit('My parents'); }}Copy the code

Emit is used to notify the parent component, which listens for events.

// parent.component.ts

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

@Component({
  selector: 'app-communicate'.templateUrl: './communicate.component.html'.styleUrls: ['./communicate.component.scss']})export class CommunicateComponent implements OnInit {

  public msg:string = ' '

  constructor() { }

  ngOnInit(): void{}fromChild(data: string) {
    // Use asynchrony here
    setTimeout(() = > {
      this.msg = data
    }, 50)}}Copy the code

In the parent component, we use the setTimeout asynchronous operation after listening on the data from the Child component. This is because we emit after initialization in the child component, where the asynchronous operation is to prevent a Race Condition Race error.

We also need to add the fromChild method to the component as follows:

<! -- parent.component.html -->

<h1>Hello! {{ msg }}</h1>
<app-child (childSayHi) ="fromChild($event)"></app-child>
Copy the code

3. By reference, the parent component obtains the properties and methods of the child component

We retrieve child component objects by manipulating references and then access their properties and methods.

Let’s first set up the child component’s demo:

// child.component.ts

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

@Component({
  selector: 'app-child'.templateUrl: './child.component.html'.styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {

  // Attributes of the child component
  public childMsg:string = 'Prop: message from child'

  constructor() { }

  ngOnInit(): void{}// Subcomponent methods
  public childSayHi(): void {
    console.log('Method: I am your child.')}}Copy the code

We set the child reference identifier #childComponent on the parent component:

<! -- parent.component.html -->

<app-child #childComponent></app-child>
Copy the code

Then call it on the javascript file:

import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from './components/child/child.component';

@Component({
  selector: 'app-communicate'.templateUrl: './communicate.component.html'.styleUrls: ['./communicate.component.scss']})export class CommunicateComponent implements OnInit {
  @ViewChild('childComponent') childComponent! : ChildComponent;constructor() { }

  ngOnInit(): void {
    this.getChildPropAndMethod()
  }

  getChildPropAndMethod(): void {
    setTimeout(() = > {
      console.log(this.childComponent.childMsg); // Prop: message from child
      this.childComponent.childSayHi(); // Method: I am your child.
    }, 50)}}Copy the code

One limitation of this method 🚫 is that the modifier of the child property must be public, and an error will be reported when protected or private. You can try changing the modifier of a child component. The reasons for the error are as follows:

type Using range
public Allows to be called in and out of tired areas, the widest range
protected Can be used within a class or in an inherited subclass, with moderate scope
private Allows use within a class with the narrowest scope

4. Use service to change

Let’s demonstrate this with RXJS.

RXJS is a library for responsive programming using Observables, which makes it easier to write asynchronous or callback-based code.

There will be an article documenting RXJS later, so stay tuned

Let’s start by creating a service called parent-and-Child.

// parent-and-child.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; // The BehaviorSubject is real-time and gets the latest values

@Injectable({
  providedIn: 'root'
})
export class ParentAndChildService {

  private subject$: BehaviorSubject<any> = new BehaviorSubject(null)

  constructor(){}// Make it observable
  getMessage(): Observable<any> {
    return this.subject$.asObservable()
  }

  setMessage(msg: string) {
    this.subject$.next(msg); }}Copy the code

We then reference the parent and child components, whose information is shared.

// parent.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';
// Import services
import { ParentAndChildService } from 'src/app/services/parent-and-child.service';
import { Subject } from 'rxjs'
import { takeUntil } from 'rxjs/operators'

@Component({
  selector: 'app-communicate'.templateUrl: './communicate.component.html'.styleUrls: ['./communicate.component.scss']})export class CommunicateComponent implements OnInit.OnDestroy {
  unsubscribe$: Subject<boolean> = new Subject();

  constructor(
    private readonly parentAndChildService: ParentAndChildService
  ) { }

  ngOnInit(): void {
    this.parentAndChildService.getMessage()
      .pipe(
        takeUntil(this.unsubscribe$)
      )
      .subscribe({
        next: (msg: any) = > {
          console.log('Parent: ' + msg); 
          // εˆšθΏ›ζ₯打印 Parent: null
          // Prints Parent: Jimmy after one second}});setTimeout(() = > {
      this.parentAndChildService.setMessage('Jimmy');
    }, 1000)}ngOnDestroy() {
    // Unsubscribe
    this.unsubscribe$.next(true);
    this.unsubscribe$.complete(); }}Copy the code
import { Component, OnInit } from '@angular/core';
import { ParentAndChildService } from 'src/app/services/parent-and-child.service';

@Component({
  selector: 'app-child'.templateUrl: './child.component.html'.styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {
  constructor(
    private parentAndChildService: ParentAndChildService
  ){}// For better understanding, I have removed the parent component's Subject here
  ngOnInit(): void {
    this.parentAndChildService.getMessage()
      .subscribe({
        next: (msg: any) = > {
          console.log('Child: '+msg);
          // εˆšθΏ›ζ₯打印 Child: null
          // Print Child: Jimmy after one second}}}})Copy the code

In the parent component, we change the value after a second. So in the parent component, the initial value of MSG, NULL, is printed as soon as it comes in, and then a second later, the changed value Jimmy is printed. Similarly, if you print information about a service in a child component, the parent component prints the relevant value as well as the child component.

【 the 】 βœ