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: