How to call a function from another component in Angular 17?

How to call a function from another component in Angular 17?

Are you working on an Angular project and need to call a function from a different component? This is a common task in Angular development, and there are a few different ways to achieve it. In this blog post, we'll explore two popular methods: using child components and utilizing services.

Method 1: Using Child Components

This method is simple and straightforward, but it requires the target component to be a direct child of the component calling the function.

1- Create a Child Component: Start by generating a new component using the Angular CLI. For example, we'll create a child component called "child".

ng generate component child
1ng generate component child

2- Define the Function in the Child Component: Within the child component's TypeScript file, define the function you want to call.

import { Component } from '@angular/core';

@Component({
  selector: 'app-child',
  standalone:true,
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss'],
  imports: [CommonModule, RouterOutlet],
})
export class ChildComponent {
  headingVisible = false; 
  showHeading(): void {
    // Your logic here
    this.headingVisible = true;
  }
}
1import { Component } from '@angular/core'; 2 3@Component({ 4 selector: 'app-child', 5 standalone:true, 6 templateUrl: './child.component.html', 7 styleUrls: ['./child.component.scss'], 8 imports: [CommonModule, RouterOutlet], 9}) 10export class ChildComponent { 11 headingVisible = false; 12 showHeading(): void { 13 // Your logic here 14 this.headingVisible = true; 15 } 16}

3- Import the Child Component: In the parent component’s TypeScript file, import the child component and add into the imports array of child.component.ts

import { Component } from '@angular/core';
import { ChildComponent } from './child/child.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  imports: [CommonModule, RouterOutlet, ChildComponent],

})
export class AppComponent {
  
}
1import { Component } from '@angular/core'; 2import { ChildComponent } from './child/child.component'; 3 4@Component({ 5 selector: 'app-root', 6 templateUrl: './app.component.html', 7 styleUrls: ['./app.component.scss'], 8 imports: [CommonModule, RouterOutlet, ChildComponent], 9 10}) 11export class AppComponent { 12 13} 14

4- Use the Child Component in the Template: Add the child component to the parent component's HTML template.

<app-child></app-child>
1<app-child></app-child>

Now, you can access the function defined in the child component using the @ViewChild decorator in the parent component's TypeScript file. In following code we added @ViewChild decorator and passed it the ChildComponent class and defined the property child on it of type ChildComponent

import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  @ViewChild(ChildComponent) child: ChildComponent;
}
1import { Component, ViewChild } from '@angular/core'; 2import { ChildComponent } from './child/child.component'; 3 4@Component({ 5 selector: 'app-root', 6 templateUrl: './app.component.html', 7 styleUrls: ['./app.component.scss'] 8}) 9export class AppComponent { 10 @ViewChild(ChildComponent) child: ChildComponent; 11} 12

5- Calling the function of child component from app component Template: In the component's template file, create a button, register the click event and call the showHeading function from the child component by using child property.

<app-child></app-child>
<button (click)="child.showHeading()">Show Child Heading<button>
1<app-child></app-child> 2<button (click)="child.showHeading()">Show Child Heading<button>

Before Button Click:

After button click:

Method 2: Using Services

This method is more flexible as it allows you to call functions between components that are not directly related.

1- Create a Service: Generate a service using the Angular CLI.

ng generate service general
1ng generate service general

2- Define the Function in the Service: In the service's TypeScript file, we added a property onButtonClick and assigned it an instance of rxjs' Subject class with data type of string.

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class GeneralService {
  onButtonClick = new Subject<string>();
}
1import { Injectable } from '@angular/core'; 2import { Subject } from 'rxjs'; 3 4@Injectable({ 5 providedIn: 'root' 6}) 7export class GeneralService { 8 onButtonClick = new Subject<string>(); 9} 10

3- Generate two components: Generate two components, sidebar and content, that would be sibling in app.component.html later.

ng generate c sidebar && ng g c content
1ng generate c sidebar && ng g c content

4- Inject the Service: In both the components, sidebar.component.ts, content.component.ts, that need to access the function, inject the service using the inject function. Make sure to import the inject function from @angular/core

// In sidebar.component.ts
import { Component, OnInit, inject } from '@angular/core';
import { GeneralService } from '../general.service';

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent {
  generalService = inject(GeneralService) 
}
1// In sidebar.component.ts 2import { Component, OnInit, inject } from '@angular/core'; 3import { GeneralService } from '../general.service'; 4 5@Component({ 6 selector: 'app-sidebar', 7 templateUrl: './sidebar.component.html', 8 styleUrls: ['./sidebar.component.scss'] 9}) 10export class SidebarComponent { 11 generalService = inject(GeneralService) 12}
// In content.component.ts
import { Component, OnInit } from '@angular/core';
import { GeneralService } from '../general.service';

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.scss']
})
export class ContentComponent  {
  generalService = inject(GeneralService) 

}
1// In content.component.ts 2import { Component, OnInit } from '@angular/core'; 3import { GeneralService } from '../general.service'; 4 5@Component({ 6 selector: 'app-content', 7 templateUrl: './content.component.html', 8 styleUrls: ['./content.component.scss'] 9}) 10export class ContentComponent { 11 generalService = inject(GeneralService) 12 13}

5- Subscribe to onButtonClick subject in SidebarComponent: Now in sidebar.component.ts implement the OnInit life cycle hook, define property headingVisible ( default value true ). 

Next in the ngOnInit method, subscribe to the onButtonClick subject and set the headingVisible property to true in the callback function of that subscribe function. 

// In sidebar.component.ts
import { Component, OnInit, inject } from '@angular/core';
import { GeneralService } from '../general.service';

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent implements OnInit {

  headingVisible = false;
  generalService = inject(GeneralService) 

  ngOnInit(): void {
    this.generalService.onButtonClick.subscribe(heading => {
      this.headingVisible = true;
    });
  }

}
1// In sidebar.component.ts 2import { Component, OnInit, inject } from '@angular/core'; 3import { GeneralService } from '../general.service'; 4 5@Component({ 6 selector: 'app-sidebar', 7 templateUrl: './sidebar.component.html', 8 styleUrls: ['./sidebar.component.scss'] 9}) 10export class SidebarComponent implements OnInit { 11 12 headingVisible = false; 13 generalService = inject(GeneralService) 14 15 ngOnInit(): void { 16 this.generalService.onButtonClick.subscribe(heading => { 17 this.headingVisible = true; 18 }); 19 } 20 21}

6- Add heading in sidebar component: In the sidebar.component.ts we will add an heading based on condition. If headingVisible is set to true then the heading would be visible otherwise it will be hidden.

<!-- in sidebar.component.html -->
@if(headingVisible){
	<h1>Heading from sidebar component</h1>
}
1<!-- in sidebar.component.html --> 2@if(headingVisible){ 3 <h1>Heading from sidebar component</h1> 4}

7- Add button in sidebar component to trigger the event: Now in sidebar.component.html, we need to add <button> tag and register the click event that will then call the next function of onButtonClick subject from GeneralService.


<!-- In sidebar.component.html -->
<button (click)="generalService.onButtonClick.next('')">Show sidebar heading</button>
1 2<!-- In sidebar.component.html --> 3<button (click)="generalService.onButtonClick.next('')">Show sidebar heading</button> 4

So here as soon as the button is clicked then the subject onButtonClick is triggered that sends signal to all subscriptions to it. In our case, we have subscribed to it in the sidebar.component.ts, so the callback function in that subscription would be executed that would set the value of the showHeading to true and hence will cause the heading tag visible in the html template file. 

====

This is just a brief introduction to calling functions between components in Angular. To explore more advanced techniques and examples, subscribe to my YouTube channel for more Angular tutorials and tips. Don't forget to like and share this post with your fellow Angular developers!

Like, Share, Subscribe!

Source Code: https://github.com/ayyazzafar/angular_17_tutorials_code/tree/call_function_from_another_component