How to call function of other components in angular2

I have two components as follows, and I want to call a function from another component. Both components are included in the third parent component using the directive.

Component 1:

@component( selector:'com1' ) export class com1{ function1(){...} } 

Component 2:

 @component( selector:'com2' ) export class com2{ function2(){... // i want to call function 1 from com1 here } } 

I tried using @input and @output , but I don’t exactly understand how to use it and how to call this function, can anyone help?

+124
angular angular2-components
Jun 02 '16 at 9:24
source share
7 answers

If com1 and com2 are siblings, you can use

 @component({ selector:'com1', }) export class com1{ function1(){...} } 

com2 emits an event using an EventEmitter

 @component({ selector:'com2', template: '<button (click)="function2()">click</button>' ) export class com2{ @Output() myEvent = new EventEmitter(); function2(){... this.myEvent.emit(null) } } 

Here, the parent component adds an event binding to listen for myEvent events, and then calls com1.function1() when such an event occurs. #com1 is a template variable that allows you to reference this element from other parts of the template. We use this to make function1() an event handler for myEvent from com2 :

 @component({ selector:'parent', template: '<com1 #com1></com1><com2 (myEvent)="com1.function1()"></com2>' ) export class com2{ } 

For other interactions between components, see also component interaction.

+109
Jun 02 '16 at 9:29
source share

First, what you need to understand the relationship between the components. Then you can choose the right way to communicate. I will try to explain all the methods that I know and use in my practice for the interaction between components.

What can be the relationship between the components?

1. Parent> Child

enter image description here

Input data exchange

This is probably the most common way to exchange data. It works with the @Input() decorator, which allows you to transfer data through a template.

parent.component.ts

 import { Component } from '@angular/core'; @Component({ selector: 'parent-component', template: ' <child-component [childProperty]="parentProperty"></child-component> ', styleUrls: ['./parent.component.css'] }) export class ParentComponent{ parentProperty = "I come from parent" constructor() { } } 

child.component.ts

 import { Component, Input } from '@angular/core'; @Component({ selector: 'child-component', template: ' Hi {{ childProperty }} ', styleUrls: ['./child.component.css'] }) export class ChildComponent { @Input() childProperty: string; constructor() { } } 

This is a very simple method. It is easy to use. We can also track data changes in a child component using ngOnChanges .

But do not forget that if we use an object as data and change the parameters of this object, the link to it will not change. Therefore, if we want to get a modified object in a child component, it must be immutable.

2. Child> Parent

enter image description here

Data exchange through ViewChild

ViewChild allows one component to be embedded in another, providing parent access with its attributes and functions. However, one caveat is that child will not be available until the view is initialized. This means that we need to implement the AfterViewInit lifecycle hook to receive data from the child.

parent.component.ts

 import { Component, ViewChild, AfterViewInit } from '@angular/core'; import { ChildComponent } from "../child/child.component"; @Component({ selector: 'parent-component', template: ' Message: {{ message }} <child-compnent></child-compnent> ', styleUrls: ['./parent.component.css'] }) export class ParentComponent implements AfterViewInit { @ViewChild(ChildComponent) child; constructor() { } message:string; ngAfterViewInit() { this.message = this.child.message } } 

child.component.ts

 import { Component} from '@angular/core'; @Component({ selector: 'child-component', template: ' ', styleUrls: ['./child.component.css'] }) export class ChildComponent { message = 'Hello!'; constructor() { } } 

Communication via Output () and EventEmitter

Another way to exchange data is to send data from a child, which can be listed by the parent. This approach is ideal when you want to share data changes that happen in things like button clicks, form entries, and other user events.

parent.component.ts

 import { Component } from '@angular/core'; @Component({ selector: 'parent-component', template: ' Message: {{message}} <child-component (messageEvent)="receiveMessage($event)"></child-component> ', styleUrls: ['./parent.component.css'] }) export class ParentComponent { constructor() { } message:string; receiveMessage($event) { this.message = $event } } 

child.component.ts

 import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'child-component', template: ' <button (click)="sendMessage()">Send Message</button> ', styleUrls: ['./child.component.css'] }) export class ChildComponent { message: string = "Hello!" @Output() messageEvent = new EventEmitter<string>(); constructor() { } sendMessage() { this.messageEvent.emit(this.message) } } 

3. Siblings

enter image description here

Child> Parent> Child

I am trying to explain other ways of communicating between brothers and sisters below. But you could already understand one way to understand the above methods.

parent.component.ts

 import { Component } from '@angular/core'; @Component({ selector: 'parent-component', template: ' Message: {{message}} <child-one-component (messageEvent)="receiveMessage($event)"></child1-component> <child-two-component [childMessage]="message"></child2-component> ', styleUrls: ['./parent.component.css'] }) export class ParentComponent { constructor() { } message: string; receiveMessage($event) { this.message = $event } } 

baby one.component.ts

 import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'child-one-component', template: ' <button (click)="sendMessage()">Send Message</button> ', styleUrls: ['./child-one.component.css'] }) export class ChildOneComponent { message: string = "Hello!" @Output() messageEvent = new EventEmitter<string>(); constructor() { } sendMessage() { this.messageEvent.emit(this.message) } } 

baby two.component.ts

 import { Component, Input } from '@angular/core'; @Component({ selector: 'child-two-component', template: ' {{ message }} ', styleUrls: ['./child-two.component.css'] }) export class ChildTwoComponent { @Input() childMessage: string; constructor() { } } 

4. Unbound components

enter image description here

All the methods that I described below can be used for all the above options for communication between components. But each has its own advantages and disadvantages.

Data exchange with the service

When transferring data between components that do not have a direct connection, such as siblings, grandchildren, etc., you must use a common service. When you have data that should always be synchronized, I find that RxJS BehaviorSubject is very useful in this situation.

data.service.ts

 import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable() export class DataService { private messageSource = new BehaviorSubject('default message'); currentMessage = this.messageSource.asObservable(); constructor() { } changeMessage(message: string) { this.messageSource.next(message) } } 

first.component.ts

 import { Component, OnInit } from '@angular/core'; import { DataService } from "../data.service"; @Component({ selector: 'first-componennt', template: ' {{message}} ', styleUrls: ['./first.component.css'] }) export class FirstComponent implements OnInit { message:string; constructor(private data: DataService) { // The approach in Angular 6 is to declare in constructor this.data.currentMessage.subscribe(message => this.message = message); } ngOnInit() { this.data.currentMessage.subscribe(message => this.message = message) } } 

second.component.ts

 import { Component, OnInit } from '@angular/core'; import { DataService } from "../data.service"; @Component({ selector: 'second-component', template: ' {{message}} <button (click)="newMessage()">New Message</button> ', styleUrls: ['./second.component.css'] }) export class SecondComponent implements OnInit { message:string; constructor(private data: DataService) { } ngOnInit() { this.data.currentMessage.subscribe(message => this.message = message) } newMessage() { this.data.changeMessage("Hello from Second Component") } } 

Exchange data with a route

Sometimes you need to not only transfer simple data between components, but also save some page state. For example, we want to save the filter in the online market, and then copy this link and send it to a friend. And we expect him to open the page in the same state as us. The first and perhaps the fastest way to do this is to use query parameters .

The request parameters are more like the lines /people?id= , where id can be anything, and you can have as many parameters as you want. Request parameters will be separated by an ampersand.

When working with query parameters, you do not need to define them in the routes file, and they can be called parameters. For example, take the following code:

page1.component.ts

 import {Component} from "@angular/core"; import {Router, NavigationExtras} from "@angular/router"; @Component({ selector: "page1", template: ' <button (click)="onTap()">Navigate to page2</button> ', }) export class Page1Component { public constructor(private router: Router) { } public onTap() { let navigationExtras: NavigationExtras = { queryParams: { "firstname": "Nic", "lastname": "Raboy" } }; this.router.navigate(["page2"], navigationExtras); } } 

On the receive page, you will receive the following request parameters:

page2.component.ts

 import {Component} from "@angular/core"; import {ActivatedRoute} from "@angular/router"; @Component({ selector: "page2", template: ' <span>{{firstname}}</span> <span>{{lastname}}</span> ', }) export class Page2Component { firstname: string; lastname: string; public constructor(private route: ActivatedRoute) { this.route.queryParams.subscribe(params => { this.firstname = params["firstname"]; this.lastname = params["lastname"]; }); } } 

Ngrx

The latter method, which is more complex but more powerful, is to use NgRx . This library is not for data exchange; It is a powerful state management library. I can’t explain in a short example how to use it, but you can go to the official website and read the documentation about it.

For me, the NgRx Store solves a few problems. For example, when you have to deal with observables and when the responsibility for some observable data is distributed between different components, the actions of the repository and reducer ensure that data changes will always be performed in the “right way”.

It also provides a reliable solution for caching HTTP requests. You will be able to store requests and their answers to make sure that your answer has not yet been saved.

You can read about NgRx and see if you need it in your application or not:

Finally, I want to say that before choosing some data exchange methods you need to understand how this data will be used in the future. I mean, maybe now you can only use the @Input decorator to share your username and last name. Then you add a new component or a new module (for example, the admin panel), which needs additional information about the user. This means that this may be the best way to use the service for user data or some other way of exchanging data. You should think about this more before you start exchanging data.

+71
Jan 17 '19 at 22:33
source share

You can access component one of component two.

Componententne

  ngOnInit() {} public testCall(){ alert("I am here.."); } 

componentTwo

 import { oneComponent } from '../one.component'; @Component({ providers:[oneComponent ], selector: 'app-two', templateUrl: ... } constructor(private comp: oneComponent ) { } public callMe(): void { this.comp.testCall(); } 

componentTwo HTML file

 <button (click)="callMe()">click</button> 
+65
Feb 15 '18 at 13:32
source share

Component 1 (child):

 @Component( selector:'com1' ) export class Component1{ function1(){...} } 

Component 2 (parent):

 @Component( selector:'com2', template: '<com1 #component1></com1>' ) export class Component2{ @ViewChild("component1") component1: Component1; function2(){ this.component1.function1(); } } 
+26
Jan 28 '18 at 13:22
source share

It depends on the relationship between your components (parent / child), but the best / universal way to create communication components is to use a shared service.

See this document for more details:

With this, you can use the following to provide an instance of com1 in com2:

 <div> <com1 #com1>...</com1> <com2 [com1ref]="com1">...</com2> </div> 

In com2, you can use the following:

 @Component({ selector:'com2' }) export class com2{ @Input() com1ref:com1; function2(){ // i want to call function 1 from com1 here this.com1ref.function1(); } } 
+25
Jun 02 '16 at 9:25
source share
  • Let's say component 1 is DbstatsMainComponent
  • 2nd component of DbstatsGraphComponent.
  • 1st component calling 2nd method

<button (click)="dbgraph.displayTableGraph()">Graph</button> <dbstats-graph #dbgraph></dbstats-graph>

Note the local variable #dbgraph in the child component, which the parent can use to access their methods ( dbgraph.displayTableGraph() ).

+1
Aug 02 '17 at 16:13
source share

Using the Dataservice, we can call a function from another component

Component1: The component that we call the function

 constructor( public bookmarkRoot: dataService ) { } onClick(){ this.bookmarkRoot.callToggle.next( true ); } 

dataservice.ts

 import { Injectable } from '@angular/core'; @Injectable() export class dataService { callToggle = new Subject(); } 

Component2: a component that contains a function

 constructor( public bookmarkRoot: dataService ) { this.bookmarkRoot.callToggle.subscribe(( data ) => { this.closeDrawer(); } ) } closeDrawer() { console.log("this is called") } 
0
Aug 21 '19 at 9:36
source share



All Articles