This time I will bring you the Angular2 parent-child component communication method. What are the precautions when using the Angular2 parent-child component communication method. The following is a practical case, let's take a look.
Angular2 official documentation has a detailed introduction to component interaction-->Documentation--Interaction between components. According to the document, there are 4 ways to interact between components, including:
Transfer data from parent component to child component through input binding (@Input decoration); child component Expose an EventEmitter property (@Output decoration), and use this property to emit events to the parent component when an event occurs.
Parent components and child components interact through local variables. (# var)
The parent component calls @ViewChild.
Parent components and child components communicate through services.
Here I will only summarize and introduce in detail three methods that I have used in the project. After reading this article, you can probably achieve the following results:
Create a project with the following project structure:
Communication between parent and child components through @Input and @Output decorators
@Input: This property binding is used by the parent component to pass data to the child component. Subcomponents can intercept property changes through the following two methods:
Use an input property setter to intercept value changes in the parent component.
Use ngOnchanges() to intercept changes in input attribute values.
@Output: This Data binding is used by child components to pass data and events to parent components.
<!--parent.component.html--> <p style="width: 1000px;margin: auto"> <p class="card" style="width: 500px;float: left"> <p class="card-header"> 父组件 </p> <p class="card-body"> <h5 class="card-title">父组件</h5> <p class="form-group"> <label for="input">父组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="parentPrint" > <label for="output">父组件输出:</label> <input type="text" class="form-control" id="output" placeholder="Output something" [(ngModel)]="contentFromChild" > </p> </p> </p> <app-child [fromParent]="parentPrint" (fromChild)="fromChild($event)" ></app-child> </p>
<!--child.component.html--> <p class="card" style="width: 500px;"> <p class="card-header"> 子组件 </p> <p class="card-body"> <h5 class="card-title">子组件</h5> <p class="form-group"> <label for="input">子组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="contentFromChild" > <label for="output">子组件输出:</label> <input type="text" class="form-control" id="output" placeholder="Output something" [(ngModel)]="fromParent" > </p> <button class="btn btn-primary" (click)="clickChild()">Output方式</button> </p> </p>
The effect is as follows: (1. Parent component input, sub-component can output synchronously; 2. Sub-component input requires (3.) Click the button to trigger the launch event and transmit the data to the parent component.)
@Input: While the parent component is inputting, the child component can simultaneously obtain data for display. The core code is as follows:
//父组件 parentPrint: any; //ts中,声明一个变量 [(ngModel)]="parentPrint" //html中,绑定变量,获取用户输入 //html中,将数据传给子组件 <app-child [fromParent]="parentPrint"></app-child> //子组件 @Input() fromParent; //ts中,用于直接接收从父组件获取的数据 [(ngModel)]="fromParent" //html中,用于显示数据
Use the setter to intercept changes in input attribute values, and declare a private variable in the child component to obtain the data passed by the parent component, thus shielding the upper layer from obtaining the lower layer information. (A simple point is not to let the parent component know what the child component uses to receive the passed data) The same effect can be obtained through this method.
//子组件 private _fromParent: any; //私有变量,通过setter获取父组件的数据 @Input() //通过setter获取父组件的数据 set fromParent(fromParent: any) { this._fromParent = fromParent; } get fromParent(): any { return this._fromParent; }
@Output: When the parent component receives data from the child component, the child component exposes an EventEmitter property. When an event occurs, the child component uses this property to emit (upward ejection) events. The parent component binds to this event property and responds when the event occurs. The core code is as follows:
//子组件 @Output() fromChild = new EventEmitter<any>(); //暴露一个输出属性 <button class="btn btn-primary" (click)="clickChild()">Output方式</button> //触发发射函数,将数据发送给父组件 clickChild() { console.log('click child' , this.contentFromChild); this.fromChild.emit(this.contentFromChild); }
//父组件 [(ngModel)]="contentFromChild" //绑定输出子组件的数据 //使用子组件,绑定事件属性 <app-child [fromParent]="parentPrint" (fromChild)="fromChild($event)" ></app-child> //事件处理函数 fromChild(event) { console.log(event); this.contentFromChild = event; }
The parent component obtains the data of the child component by calling @ViewChild()
If the class of the parent component needs to read the properties and properties of the child component When you add a value or call a method of a subcomponent, you can inject the subcomponent into the parent component as ViewChild. ViewChild, as its name implies, means that you can see the properties and methods in the subcomponent.
<!--parent.component.html--> <p style="width: 1000px;margin: auto"> <p class="card" style="width: 500px;float: left"> <p class="card-header"> 父组件 </p> <p class="card-body"> <h5 class="card-title">父组件</h5> <p class="form-group"> <label for="viewoutput">ViewChild父组件输出:</label> <input type="text" class="form-control" id="viewoutput" placeholder="ViewChild父组件输出" [(ngModel)]="viewOutput" > </p> <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button> </p> </p> <app-child></app-child> </p>
<!--child.component.html--> <p class="card" style="width: 500px;"> <p class="card-header"> 子组件 </p> <p class="card-body"> <h5 class="card-title">子组件</h5> <p class="form-group"> <label for="input">子组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="contentFromChild" > </p> </p> </p>
The effect is as follows:
Core code of parent component:
//ts @ViewChild(ChildComponent) // 使用viewChild导入引用 private childComponent: ChildComponent; // 将子组件注入到私有属性 //获取子组件数据并显示 clickView() { //直接获取子组件的属性 this.viewOutput = this.childComponent.contentFromChild; }
//html [(ngModel)]="viewOutput" <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
Parent component and child component communicate through services
The parent component and its child components share the same service and use this service to achieve two-way communication within the family.
<!--parent.component.html--> <p style="width: 1000px;margin: auto"> <p class="card" style="width: 500px;float: left"> <p class="card-header"> 父组件 </p> <p class="card-body"> <h5 class="card-title">父组件</h5> <p class="form-group"> <label for="serviceoutput">父组件服务输入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服务输入" [(ngModel)]="serviceInput" > </p> <button class="btn btn-primary" (click)="clickService()">Service方式</button> </p> </p> <app-child></app-child> </p>
<!--child.component.html--> <p class="card" style="width: 500px;"> <p class="card-header"> 子组件 </p> <p class="card-body"> <h5 class="card-title">子组件</h5> <p class="form-group"> <label for="serviceoutput">子组件服务输入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服务输入" [(ngModel)]="serviceInput" > </p> <button class="btn btn-primary" (click)="clickService()">Service方式</button> </p> </p>
//服务 //meditor.service.ts import {Injectable} from '@angular/core'; import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable'; @Injectable() export class MeditorService { private subject = new Subject<MeditorMsg>(); constructor() {} // 获取订阅者 public getObservable(): Observable<MeditorMsg> { return this.subject.asObservable(); } // 推送信息 public push(msg: MeditorMsg) { this.subject.next(msg); } } // 中间者信息 export interface MeditorMsg { id: string; body: any; }
The effect is as follows:
The core code of the parent and child components is similar, inject the service instance into itself in the constructor, Both parent and child components have a unique id. Whether the parent component or the child component calls the push() method to push data, both parties can receive the data. At this time, it is necessary to determine whether the parent component or the child component uses the data based on the ID. The core code is as follows:
subscription: Subscription = null; //初始化一个订阅对象 //子组件构造函数,用于监听数据推送 constructor( private meditor: MeditorService ) { this.subscription = meditor.getObservable().subscribe( msg => { console.log(msg); if (msg.id === 'parent') { //id为parent,获取父组件数据 this.serviceInput = msg.body; } } ); } // 子组件将数据推送到中间着,给订阅者 clickService() { this.meditor.push({id: 'parent', body: this.serviceInput}); } //父组件构造函数,用于监听数据推送 constructor( private meditor: MeditorService ) { this.subscription = meditor.getObservable().subscribe( msg => { console.log(msg); if (msg.id === 'child') { //id为child,获取子组件数据 this.serviceInput = msg.body; } } ); } // 父组件将数据推送到中间着,给订阅者 clickService() { this.meditor.push({id: 'parent', body: this.serviceInput}); }
我上面写的还不是很完善,就是在生命周期结束前,也就是在onDestroy周期中,要取消订阅。
以上,就是最近在使用的组件交互的总结。个人觉得通过服务来交互的可扩展性更强。例如,我们项目中用到了一个动态显示的侧栏,不同时期点击显示侧栏要显示不同的东西。这个时候把侧栏作为父组件,子组件作为消息的一部分传递给父组件,父组件根据子组件名动态生成模板,显示在侧栏上面。说了这么多废话大概就是下图的意思:
最后附上demo源码:父子组件交互demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Angular2 parent-child component communication method. For more information, please follow other related articles on the PHP Chinese website!