February 24, 2022

Angular - Receive event notification from child component

Angular enables the components based development which helps you create small cohesive components to design the application in a manageable approach. This may also lead to a complex heirarchy among the components. Then you need a mechanism to communicate between these components which may be in two directions top-down and bottom-up.

In this post we will see an example of bottom-up approach to allow communication from the child component to the parent component.

Lets say we have two components, ParentComponent and ChildComponent, with structure like this.

<parent-component>
    <child-component />
</parent-component>

The child-component has a button called btnSearch, which needs to invoke the parent-component's function searchCalledByChild();

Lets walk through this example to see how we can achieve this behavior.

This is the child component's ts file:

// child.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-child-component',
  templateUrl: './child-component.component.html',
  styleUrls: ['./child-component.component.css']
})
export class ChildComponentComponent implements OnInit {
  count: number = 0;
  child_msg : string = "";

  constructor() { }

  ngOnInit(): void {
  }
  
  btnSearchClicked() {
    this.child_msg = "Clicked Counter: " + this.count++;
  }
}

This will display a string child_msg in html template, showing the counter for button clicks.

This is the parent component's ts file:

// parent.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent implements OnInit {
	
  parent_msg : string = "";
  chil_msg_inside_parent : string = "";

 constructor() { }

  ngOnInit(): void {
  }
	
  //method in parent class, this needs to be invoked 
  //when button is clicked in child component
  searchCalledByChild(child_msg_received: string)
  {	
    this.parent_msg = "Message from parent component";
		
    //child_msg_received is the data passed from child component.
    this.chil_msg_inside_parent = child_msg_received;
  }
}

To enable the parent component to receive notification of child-component's event, we have to makes these changes in child-component's ts file:

First import Output and EventEmitter from '@angular/core'

import { Output, EventEmitter } from '@angular/core';

Decorate a property with @Output(). Here searchButtonClickedEvent is the name of the property declared as EventEmitter, which means it's an event.

@Output() searchButtonClickedEvent = new EventEmitter<string>();

The type parameter we passed to EventEmitter<> tells angular that this event will emit the string data.

Raise this event from child-component's local method btnSearchClicked() using the emit() function.

btnSearchClicked() 
{
   this.child_msg = "Clicked Counter: " + this.count++;

   this.searchButtonClickedEvent.emit(this.child_msg);
}

Here is the html template for child-component:

<div style="background-color:grey;margin:10px;padding:10px;">
   <button id="btnSearch" (click)="btnSearchClicked()">Click child</button>
   <p>Child Content: {child_msg}}</p>
</div>

Now the child component is ready to emit events whenever the btnSearchClicked() function is called. In this example we are calling this function from child-component's button click.

To enable the parent-component to receive this event, we will bind the parent' local method to the child's event. To bind the event we will use the same event property of EventEmitter we have defined in the child-component.

<div style="background-color:tan;margin:10px; padding:10px;">
   
   <app-child-component 
         (searchButtonClickedEvent)="searchCalledByChild($event)">
   </app-child-component>
   
   <p>{{parent_msg}}</p>
   <p>Parent Content: {{chil_msg_inside_parent}}</p>
   
</div>

This event binding, (searchButtonClickedEvent)="searchCalledByChild($event), connects the event in the child (searchButtonClickedEvent) to the function in the parent(searchCalledByChild).

The $event parameter contains the data that we have passed from the child-compoment in the emit() function.

The complete listing of the parent-component's ts file will be look like this:

// parent.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent implements OnInit {
	
  parent_msg : string = "";
  chil_msg_inside_parent : string = "";

 constructor() { }

  ngOnInit(): void {
  }
	
  //method in parent class, this needs to be invoked 
  //when button is clicked in child component
  searchCalledByChild(child_msg_received: string)
  {	
    this.parent_msg = "Message from parent component";
		
    //child_msg_received is the data passed from child component.
    this.chil_msg_inside_parent = child_msg_received;
  }
}

References:

Related Post(s):

Angular-Redux/Store Missing Dependencies Error

I was trying to use redux in my Angular 11.0.4 application but I was getting error as:

Error: The target entry-point "@angular-redux/store" has missing dependencies 
- redux-devtools-extension

I installed the following dependencies, which helps fix above error:

  • npm install redux --save
  • npm install redux-devtools --save
  • npm install redux-devtools-extension --save

If you get the following error:

  error TS2420: Class 'NgRedux' incorrectly implements interface 'ObservableStore'.
  Property '[Symbol.observable]' is missing in type 'NgRedux' 
  but required in type 'ObservableStore'.

It is because of the versions conflict among redux packages. To fix this, uninstall above packages and install with specific versions. For Angular 11.0.4, I found following packages helpful:

  • npm install --save redux@4.0.1
  • npm install --save @angular-redux/store@^9