1. 程式人生 > >Angular父元件和子元件通過服務來通訊

Angular父元件和子元件通過服務來通訊

我們在Angular中可以通過服務來實現子元件和父元件資料的雙向流動。
在這裡插入圖片描述
這張圖揭示了子元件和父元件通過服務來通訊的原理。
我們先用ng new parent-child來建立一個工程。接下來我們用以下命令生成相應的元件和服務。
生成父元件:
在這裡插入圖片描述
生成子元件:
在這裡插入圖片描述
生成服務:
在這裡插入圖片描述
整個工程的目錄結構如下:
在這裡插入圖片描述
如果要讓資料在多個元件中流動的話,我們就會想到多播,然後我們自然就會想到RxJS中的Subject物件。
共享服務parent.service.ts檔案的程式碼如下:

import { Injectable } from '@angular/core';
import { Subject } from
'rxjs'; @Injectable() export class ParentService { // 資料來源 next(發射資料) private parentToChildSource = new Subject<string>(); private childToParentSource = new Subject<string>(); // 資料流 subscribe(取得資料),在元件中需要訂閱 public parentToChild$ = this.parentToChildSource.asObservable(); public
childToParent$ = this.childToParentSource.asObservable(); constructor() { } public parentToChild(parentDataItem: string) { this.parentToChildSource.next(parentDataItem); } public childToParent(childDataItem: string) { this.childToParentSource.next(childDataItem); } }

父元件具體的程式碼如下:

import { Component, OnInit } from '@angular/core';
import { ParentService } from './parent.service';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
  providers: [ParentService]
})
export class ParentComponent implements OnInit {
  /**
   * 父元件資料
   * @type {[string , string , string]}
   */
  public parentData = ['來自父元件資料a', '來自父元件資料b', '來自父元件資料c'];
  /**
   * 儲存來自子元件資料
   * @type {Array}
   */
  public dataFromChild = [];
  public nextData = 0;
  constructor(private parentService: ParentService) {
    parentService.childToParent$.subscribe(data => {
      this.dataFromChild.push(`${data}`);
    });
  }

  ngOnInit() {
  }

  /**
   * 發射資料到子元件
   */
  public emissionDataToChild() {
    const toChildData = this.parentData[this.nextData++];
    this.parentService.parentToChild(toChildData);
    if (this.nextData >= this.parentData.length) { this.nextData = 0; }
  }

}

父元件模板的程式碼如下:

<p>
  <button (click)="emissionDataToChild()">發射資料給子元件</button>
</p>
<ul>
  <li *ngFor="let data of dataFromChild">{{data}}</li>
</ul>
<fieldset>
  <legend>子元件部分:</legend>
  <app-child></app-child>
</fieldset>

子元件具體的程式碼如下:

import { Component, OnDestroy } from '@angular/core';
import { ParentService } from '../parent/parent.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnDestroy {
  /**
   * 子元件的資料
   * @type {[string , string , string]}
   */
  public childData = ['來自子元件資料a', '來自子元件資料b', '來自子元件資料c'];
  /**
   * 儲存來自父元件資料
   * @type {Array}
   */
  public dataFromParent = [];
  public nextData = 0;
  public subscription: Subscription;
  constructor(private parentService: ParentService) {
    this.subscription = parentService.parentToChild$.subscribe(data => {
      this.dataFromParent.push(`${data}`);
    });
  }

  /**
   * 發射資料到父元件
   */
  public emissionDataToParent() {
    const toParentData = this.childData[this.nextData++];
    this.parentService.childToParent(toParentData);
    if (this.nextData >= this.childData.length) { this.nextData = 0; }
  }

  public ngOnDestroy() {
    this.subscription.unsubscribe();
  }

}

子元件模板的程式碼如下:

<p>
  <button (click)="emissionDataToParent()">發射資料到父元件</button>
</p>
<ul>
  <li *ngFor="let data of dataFromParent">{{data}}</li>
</ul>

因為服務可以很方便的注入到其它的元件當中,又因為Subject物件可以將資料多播(傳遞)給訂閱了這個物件的元件,因此結合Angular中的service和Rxjs中的Subject可以很方便的實現元件間的資料通訊。
最終程式碼大家可以到這裡來下載:
父元件與子元件通過服務來通訊