Home  >  Article  >  Web Front-end  >  How to implement parent-child component communication in Angular2

How to implement parent-child component communication in Angular2

亚连
亚连Original
2018-06-09 10:37:101915browse

This article mainly introduces examples of the Angular2 parent-child component communication method. Now I share it with you and give it as a reference.

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:

  1. 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.

  2. Parent components and child components interact through local variables. (# var)

  3. The parent component calls @ViewChild.

  4. 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:

  1. Use an input property setter to intercept value changes in the parent component.

  2. 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(&#39;click child&#39; , 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, allows you to see the properties and methods in subcomponents.

<!--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 &#39;@angular/core&#39;;
import {Subject} from &#39;rxjs/Subject&#39;;
import {Observable} from &#39;rxjs/Observable&#39;;

@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. In the constructor, the service instance is injected into itself. The 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 === &#39;parent&#39;) {   //id为parent,获取父组件数据
     this.serviceInput = msg.body;
    }
   }
  );
 }
// 子组件将数据推送到中间着,给订阅者
clickService() {
  this.meditor.push({id: &#39;parent&#39;, body: this.serviceInput});
 }
//父组件构造函数,用于监听数据推送
constructor(
  private meditor: MeditorService
 ) {
  this.subscription = meditor.getObservable().subscribe(
   msg => {
    console.log(msg);
    if (msg.id === &#39;child&#39;) {    //id为child,获取子组件数据
     this.serviceInput = msg.body;
    }
   }
  );
 }
// 父组件将数据推送到中间着,给订阅者
clickService() {
  this.meditor.push({id: &#39;parent&#39;, body: this.serviceInput});
 }

What I wrote above is not very complete, that is, before the end of the life cycle, that is, during the onDestroy cycle, the subscription must be cancelled.

The above is a summary of the component interactions that have been used recently. Personally, I feel that interaction through services is more scalable. For example, our project uses a dynamically displayed sidebar. Clicking to display the sidebar at different times will display different things. At this time, the sidebar is used as the parent component, and the child component is passed to the parent component as part of the message. The parent component dynamically generates a template based on the name of the child component and displays it on the sidebar. After talking so much nonsense, the following picture probably means:

The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.

Related articles:

PHP closures and anonymous functions (detailed tutorial)

How to use the three-level linkage selector in the WeChat applet

How to use jquery to achieve the accordion effect

The above is the detailed content of How to implement parent-child component communication in Angular2. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn