5-9.Angular 入門教學 - 父元件和子元件透過服務來通訊(官網範例解說)

Angular 入門教學


有關元件之間的互動教學,就用官網這個例子來做一個結尾

那官網這個例子,如果你是新手,鐵定直接卡關

卡關的原因有二,第一個就是出現了Rxjs的語法

那這是一個常會出現在前端的一個語法,雖然往後會一直出現,但我這邊是教Angular所以不會教這部分

想說的話可以Google搜尋Rxjs,可以看以下兩篇,在初學階段已經很夠用了

第二就是官網這個範例,就單純為示範他的語法功能而生出的範例

完全沒有任何實務上的目的,所以也無發從目的推導出他在做甚麼事情

這也是新手看教學文章常常看不懂的地方,所以例子就只是為示範而示範,但本身沒有實務上的目的

所以我的例子盡量都會舉有實務上的目的例子,讓大家能有一個感覺,知道說,喔~這個功能原來是用在這個地方


那接著就要開始講解官網的範例

首先我們要創一個MissionService

ng g s Mission
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

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

  // Observable string sources
  private missionAnnouncedSource = new Subject<string>();
  private missionConfirmedSource = new Subject<string>();

  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();

  // Service message commands
  announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);
  }

  confirmMission(astronaut: string) {
    this.missionConfirmedSource.next(astronaut);
  }
}

這個Sevice有兩個Observable可供外部定閱用

另外有兩個方法,會送出值給定閱的人

接著創一個父親的MissionControlComponent

ng g c MissionControl
import { Component, OnInit } from '@angular/core';
import { MissionService } from '../Services/mission.service';

@Component({
  selector: 'app-mission-control',
  templateUrl: './mission-control.component.html',
  styleUrls: ['./mission-control.component.scss']
})
export class MissionControlComponent {
  astronauts = ['Lovell', 'Swigert', 'Haise'];
  history: string[] = [];
  missions = ['Fly to the moon!',
              'Fly to mars!',
              'Fly to Vegas!'];
  nextMission = 0;

  constructor(private missionService: MissionService) {
    missionService.missionConfirmed$.subscribe(
      astronaut => {
        this.history.push(`${astronaut} confirmed the mission`);
      });
  }

  announce() {
    const mission = this.missions[this.nextMission++];
    this.missionService.announceMission(mission);
    this.history.push(`Mission "${mission}" announced`);
    if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
  }
}

父親這邊開頭就先定閱任務確認的服務,當有新的值送來,就會push一條新的訊息到畫面上

而當按下announce()則是會派發一個新的任務下去,透過MissionService的方法,可以送給有定閱該服務的人知道有新的任務

接著再創子元件AstronautComponent

ng g c Astronaut
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { MissionService } from 'src/app/Services/mission.service';

@Component({
  selector: 'app-astronaut',
  templateUrl: './astronaut.component.html',
  styleUrls: ['./astronaut.component.scss']
})
export class AstronautComponent implements OnDestroy {
  @Input() astronaut = '';
  mission = '<no mission announced>';
  confirmed = false;
  announced = false;
  subscription: Subscription;

  constructor(private missionService: MissionService) {
    this.subscription = missionService.missionAnnounced$.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    });
  }

  confirm() {
    this.confirmed = true;
    this.missionService.confirmMission(this.astronaut);
  }

  ngOnDestroy() {
    // prevent memory leak when component destroyed
    this.subscription.unsubscribe();
  }
}

兒子這邊則是一開始先定閱有沒有任務的服務,如果有值送過來就會開啟確認按鈕可以點選

當點選按鈕後,會透過MissionService方法,送出以點選確認的消息,那有定閱任務確認的人就會收到訊息

astronaut.component.html

<p>
    {{astronaut}}: <strong>{{mission}}</strong>
    <button type="button" (click)="confirm()" [disabled]="!announced || confirmed">
        Confirm
    </button>
</p>

mission-control.component.html

<h2>Mission Control</h2>
<button type="button" (click)="announce()">Announce mission</button>

<app-astronaut *ngFor="let astronaut of astronauts" [astronaut]="astronaut">
</app-astronaut>

<h3>History</h3>
<ul>
    <li *ngFor="let event of history">{{event}}</li>
</ul>

以上是畫面的安排,就不特別說明了,最後就將我們的父元件標籤放在app就完成了

<app-mission-control></app-mission-control>

那影片會有更詳細的解說,想看整個流程可以看影片

那我之前的範例是很單純的透過Service註冊在根目錄可以共用變數和方法來做溝通

那這邊是透過定閱服務,來做父子元件的溝通

嚴格說起來,我的例子有點只是大家去讀同一個變數

而這個例子透過定閱的方式,確實比較像在溝通XD

但能做到的事情其實是一樣的,但定閱用起來可以更優雅,更適合更多的複雜情境

如果情境沒很複雜,其實使用共用變數的方式就好了




Copyright © 凱哥寫程式 2022 | Powered by TalllKai ❤