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

January 24, 2022

Angular - Call child component method from parent 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 top-down approach to allow communication from the parent component to the child component.

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

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

The parent-component has a button called Search, which needs to invoke the child-component's method loadData();

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 } from '@angular/core';

@Component({
    selector: 'child-component',
    template: '<p>{{ message }}</p>'
})

class ChildComponent {
    message: String = 'Hello World!';

    loadData() {
        console.log('loading data from service');
    }
}

This is the parent component's ts file:

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

@Component({
    selector: 'parent-component',
    template: `
        <child-component />
	<button (click)="parentLocalMethod()">Call Child Component Method</button>    
	`
})

export class ParentComponent {

    parentLocalMethod() {
	//here we need to call the child component's method
    }
}

To enable the parent component to invoke child-component's method, we have to makes these changes in parent-component's ts file:

First import ViewChild from '@angular/core'

import { Component, OnInit, ViewChild  } from '@angular/core';

Import the ChildComponent class iteself:

import { ChildComponent } from '../components/child.component';

To enable the access for child-component, we can inject the child component into the parent with the help of ViewChild decorator.

@ViewChild('childComponentTemplateVariable') tempChildComponent: ChildComponent;

Where childComponentTemplateVariable passed to the ViewChild decorator is the template variable (with # symbol) we need to set in the parent template's html for child-component tag:

<child-component #childComponentTemplateVariable />

Finally we can call the child-component's method by using the variable we have defined with ViewChild decorator. Like:

tempChildComponent.loadData();

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

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

@Component({
    selector: 'parent-component',
    template: `
        <child-component #childComponentTemplateVariable />
	<button (click)="parentLocalMethod()">Call Child Component Method</button>    
	`
})

export class ParentComponent {

    @ViewChild('childComponentTemplateVariable') tempChildComponent: ChildComponent;

    parentLocalMethod() {
	//calling child-component's method
	tempChildComponent.loadData();
    }
}

ngAfterViewInit

When working with child components using the ViewChild decorator, an important thing to consider is the ngAfterViewInit lifecycle hook.

Respond after Angular initializes the component's views and child views, or the view that contains the directive.

The child component isn't available until after Angular displays the parent view. So if you are planning to process something once the view is loaded, then the best approach could be to use the ngAfterViewInit lifecycle hook to process any initialization code.

In the example above, we have called the child-components method from a button click event on the parent-component.

In case if we need to call the child-components method right after the view is loaded, then we can use the lifecycle hook ngAfterViewInit. To use the ngAfterViewInit we have to import the reference for the interace AfterViewInit and then define the ngAfterViewInit hook body.


import { Component, OnInit, ViewChild, AfterViewInit  } from '@angular/core';

//...

ngAfterViewInit() {
tempChildComponent.loadData();
}

References:

Related Post(s):

January 20, 2022

What is Redux Library

When the application size grows in terms of codebase and number of components, the state management become one of the major issues. There are many different options to achieve centeral state management, one of which is the Redux library.

Redux is a library for managing and updating application state. It helps you manage the "global" state that is required by different parts of your application. Redux serves as a centralized store for state that needs to be accessed across the entire application. It asks you to follow certain restrictions and rules to ensure that the state can only be updated in a certain manner to achieve a predictable behavior.

Redux is useful in scenarios like:

  • Large amount of application state is needed to be shared in different parts of the app
  • The app state is updated frequently
  • Application has complex logic for state update
  • Large application codebase

Redux organizes the application state in a single data structure called as store. The different components of the application read the state from this store. Having the restrictive rules, it ensures that the store is never be mutated directly. A reducer function is used to make the new state by combining the old state and the mutations defined by the action.

Following are the basic elements of Redux:

  • Store

    The store is a single JS object. Usually you need to add a TypeScript file to the project with a new interface type declaration. This interface will contain all the properties that are required to keep in the store.

  • Actions

    Actions are plain JS objects that represent something that has happened or triggered. Can be compared to events.

  • Reducers

    A reducer is a function that specifies the logic how the state changes in response to an action (or event). An important point here is the fact that a reducer function does not modify the state, it always returns a new state object by merging the old state object with the new modifications.

    A reducer function must always be a pure function, means that the function must ensure that if the same input is provided, then always the same output is produced.

    For example, the following reducer function takes the old state and return the increment by adding 1 to the the state property count. This way, it will always return the same new state if the old state do not have any changes. Hence the the same input will always produce the the same output.

    function reducer(state, action) {
      switch (action.type) {
    	case: 'INCREMENT':
    	   return { count: state.count + 1 };
      }
    }
    	

References:

December 23, 2021

Angular - Using RxJS Operators mergeMap and concatMap

The Angular MergeMap and ConcatMap are used to map each value from the source observable into an inner observable. It internally subscribes to the source observable, and then starts emitting the values from it, in palce of the original value. A new inner observable will be created for every value it receives from the Source. It merges the values from all of its inner observables and emits the values back into the stream.

Difference between MergeMap and ConcatMap is that ConcatMap maintains the order of its inner observables, while MergeMap can process the source observables in any order depending on the execution time-period of each observable.

ConcatMap operator

ConcatMap processes the source observables in a serialized fashion waiting for each one to complete before moving to the next.

Lets see any example:

////on the top of the file, import the operator
//import { concatMap } from 'rxjs/operators';

//an observable of numbers (milliseconds), we use as its values to cause the delay 
const source = of(2000, 1000);

// map value from source into inner observable, once its completes, then it will move to next value in the source observable
const newSource = source.pipe(
  concatMap(val => of(`Delayed by: ${val} ms`).pipe(delay(val))) //creates a new observable, the following section is actually subscribe to this observable
);

//subscribe to the new observable (internally created by concatMap)
const subscribe = newSource.subscribe(val =>
  console.log(`With concatMap: ${val}`)
);

This code is performing the following actions:

  • A source observable is defined with two values 2000 and 1000 representing milliseconds.
  • concatMap is used to receive values from source and emit its own values from the new observable. Before emitting the value, the inner observable is calling the delay function to simulate delay in execution. As per the values provided in the source observable, first value cause delay for 1 second and second value will cause a delay for 2 seconds.
  • The new observable is assigned to the variable newSource.
  • In the end, we subscribe to the newSource observable, and write the output to the console.

Here is the sample output from above code:

With concatMap: Delayed by: 2000 ms 
With concatMap: Delayed by: 1000 ms

From this output, its clear that the concatMap will keep the original order of values emitted from the source. The values are being displayed in the same order as we supplied in the source observable. Even the second value has shorter delay of 1 second, but it will wait for the first value (with longer delay of 2 seconds) to complete before moving to next value in the source observable.

The concatMap assures the original sequence of values. If we have multiple inner Observables, the values will be processed in sequential order. Next value will only be processed after the previous one is completed.

MergeMap operator

MergeMap is similar to the contactMap with one difference that it processes the source observables without any assurance of the order of provided values.

Lets see any example, we use the same source observable (used in above exmaple):

////on the top of the file, import the operator
//import { mergeMap } from 'rxjs/operators';

//an observable of numbers (milliseconds), we use as its values to cause the delay 
const source = of(2000, 1000);

// map value from source into inner observable, it will move to next value (whenever available) in the source observable, will not wait for the previous one to complete
const newSource = source.pipe(
  mergeMap(val => of(`Delayed by: ${val} ms`).pipe(delay(val))) //creates a new observable, the following section is actually subscribe to this observable
);

//subscribe to the new observable (internally created by mergeMap)
const subscribe = newSource.subscribe(val =>
  console.log(`With mergeMap: ${val}`)
);

This code is performing the following actions:

  • A source observable is defined with two values 2000 and 1000 representing milliseconds.
  • mergeMap is used to receive values from source and emit its own values from the new observable. Before emitting the value, the inner observable is calling the delay function to simulate delay in execution. As per the values provided in the source observable, first value cause delay for 1 second and second value will cause a delay for 2 seconds.
  • The new observable is assigned to the variable newSource.
  • In the end, we subscribe to the newSource observable, and write the output to the console.

Here is the sample output from above code:

With mergeMap: Delayed by: 1000 ms 
With mergeMap: Delayed by: 2000 ms

From this output, we know that the mergeMap do not keep the original order of values emitted from the source. The values can be displayed in the order of their execution time-period. The sooner the value is processed, it will be emitted to the subscription. Since the second value has shorter delay of 1 second, it does not wait for the first value (with greater delay of 2 seconds) to complete, and hence it gets processed before the first.

The mergeMap does not assure the original sequence of values. If we have multiple inner Observables, the values may be overlapped over time, because values will be emitted in parallel.

References:

Related Post(s):