我们在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可以很方便的实现组件间的数据通讯。
最终代码大家可以到这里来下载:
父组件与子组件通过服务来通讯