Create a Parent-Child Component in Angular

Introduction

 
In this post, we will learn about Container and Presentation components communication in Angular with sample projects. To understand Container and Presentation components, please refer to the below post.

Add Modules and Components

 
Prerequisites
  • Visual Studio Code
  • Node JS and NPM
  • Angular 8 or above
  • Angular CLI 
We need to create below modules and components. Navigate to the project root path and run the below commands in Angular CLI.
  1. ng g m employee    
  2. ng g c employee    
  3. ng g c employee/employee-list    
  4. ng g c employee/employee-detail   
The above command will create the "employee" module and component. It also creates "employee-list" and "employee-detail" presentation components.
 

Create an Interface model

 
We need to create an "Employee" Interface model so that we can use this model in our components and service. 
  1. export interface Employee {  
  2.     id: number;  
  3.     name: string;  
  4.     email: string;     
  5. }  

Create a Data Service

 
We will create an "EmployeeData" service which we will use it in components and run the below command to create data service. 
  1. ng g s core/services/employeedata  
Add the below code in the "EmployeeData" service. We have added hardcoded values for employee data and will change later to read it from another service. Also, I added the "getEmployees" method to return data. 
 
On line 03, we have used the "Employee" interface model which we created in the above step. 
  1. export class EmployeeDataService {  
  2.   
  3. employees: Employee[] = [  
  4.   {  
  5.     id: 1,  
  6.     name: 'Test Name1',  
  7.     email: 'Test Address',  
  8.     address: null  
  9.   },  
  10.   {  
  11.     id: 1,  
  12.     name: 'Test Name2',  
  13.     email: 'Test Address2',  
  14.     address: null  
  15.   },  
  16.   {  
  17.     id: 1,  
  18.     name: 'Test Name3',  
  19.     email: 'Test Address3',  
  20.     address: null  
  21.   }  
  22. ];  
  23.   
  24. getEmployees(): Observable<Employee[]> {  
  25.   return of(this.employees);  
  26. }  
  27.   
  28. }  

Use the Data Service

 
We will inject the "employeeData" service in "employee.component.ts" and consume the "getEmployees" method.
  • Line 03, employeedata service reference got added.
  • Line 15, employeedata service injected in constructor.
  • Line 18, we have created "getEmployees" local method which will get data form "employeeData" service.
  1. import { Component, OnInit } from '@angular/core';    
  2. import { Employee } from '../shared/interfaces';  
  3. import { EmployeeDataService } from '../core/services/employeedata.service';  
  4.   
  5. @Component({  
  6.   selector: 'app-employee',  
  7.   templateUrl: './employee.component.html',  
  8.   styleUrls: ['./employee.component.css']  
  9. })  
  10. export class EmployeeComponent implements OnInit {  
  11.   
  12.   public employee: Employee;  
  13.   public employees: Employee[];  
  14.   
  15.   constructor(private employeeService: EmployeeDataService) { }  
  16.   
  17.   ngOnInit(): void {  
  18.     this.getEmployees();  
  19.   }  
  20.   
  21.   getEmployees() {  
  22.     this.employeeService.getEmployees()  
  23.     .subscribe((emps: Employee[]) => this.employees = emps);  
  24.   }    
  25. }  

Update Parent component HTML

 
Add the below code in "employee.component.html" to reder the "employee-list" and "employee-detail" presentation components. Line:03 added "employeeSelected" which will trigger the rendering of "employee-detail" component.
  1. <div class="row">  
  2.     <div class="col-md-6">  
  3.         <app-employee-list [employees]="employees" (employeeSelected)='selected($event)'></app-employee-list>  
  4.     </div>  
  5.     <div class="col-md-6">  
  6.         <app-employee-detail [employee]="employee"></app-employee-detail>         
  7.     </div>  
  8. </div>  
We need to implement the "employeeSelected" event in "employee.component.ts" file as shown below. 
  1. selected(employee: any){  
  2.    this.employee = employee;  
  3.  }  

Update Presentaion components

 
We need to add the below code in the "employee-list.component.ts" file. we implemented the "selectEmployee" method and added the "employee" input, and "employeeSelected" output properties. 
  1. export class EmployeeListComponent implements OnInit {  
  2.   
  3. @Input() public employees: Employee[];  
  4. @Output() public employeeSelected = new EventEmitter<Employee>();  
  5. public bsModalRef: BsModalRef;  
  6.   
  7. constructor(private modalService: BsModalService) {}  
  8.   
  9.   ngOnInit(): void {  
  10.   }  
  11.   
  12.   selectEmployee(emp: Employee) {  
  13.     this.employeeSelected.emit(emp);     
  14.   }  
  15.   
  16. }  
Add the below code in the file, it renders the list of "employees" from the "employee" partent compontent. 
  1. <h4>Employees</h4>  
  2. <table class="table table-striped">  
  3.   <tr>  
  4.     <th>Name</th>  
  5.     <th>Email</th>  
  6.   </tr>  
  7.   <tr *ngFor="let emp of employees" (click)="selectEmployee(emp)">  
  8.     <td>{{ emp.name }}</td>  
  9.     <td>{{ emp.email }}</td>  
  10.   </tr>  
  11. </table>  
  12. <br />  
We need to add the below code in "employee-detail.component.html". It simply renders the name and email properties from the "employee" parent component.
  1. <div>  
  2.           Name: {{employee.name}}  
  3.           <br/>  
  4.           Email: {{employee.email}}  
  5.           <br/>  
  6.       </div>  
In "employee-detail.component.ts" we need to add the below "Input" Property. 
  1. @Input() public employee: Employee;  

Run and check the application

 
If we run the application, we can see the list of employees first.
 
When we click any employee row, the employee details are loaded.
 
 

Add the Modal popup

 
Instead of showing the employee detail inside, we will try to show it in the "Modal" popup page. Add "bootstrap" and "ngx-bootstrap" modules in our application.
 
After installing the bootstrap pcakges, add the below code in "styles.css" file. There are many ways to import "bootstrap" below is one of the ways.
  1. @import "~bootstrap/dist/css/bootstrap.css"  
Then do the below changes in the "AppModule.ts" file:
  • Import the "ngx-bootstrap" namespaces - "import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';" and "import { ModalModule } from 'ngx-bootstrap/modal';"
  • Add this module in "imports" - ModalModule.forRoot().
  • Add these "providers: [BsModalService, BsModalRef]," 
 In "employee-list.component.ts" add the below reference and code. Line 05-07 are important to pass the data to Modal pop-up. 
  1. import { EmployeeDetailComponent } from '../employee-detail/employee-detail.component';  
  2.   
  3. selectEmployee(emp: Employee) {  
  4.     this.employeeSelected.emit(emp);  
  5.     const initialState = {  
  6.      employee: emp  
  7.     };  
  8.     this.bsModalRef = this.modalService.show(EmployeeDetailComponent, {initialState});  
  9.     this.bsModalRef.content.closeBtnName = 'Close';  
  10.   }  
 In "employee-detail.component.ts" file add the below reference and injector.
  1. import { BsModalRef } from 'ngx-bootstrap/modal';  
  2.    
  3.  constructor(public bsModalRef: BsModalRef) { }  
Now run the application and test it.
 
 
Added Below Code for Reference
 
AppModule.ts:
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';    
  3. import { AppRoutingModule } from './app-routing.module';  
  4. import { AppComponent } from './app.component';  
  5. import { EmployeeModule } from './employee/employee.module';  
  6. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  7. import { ModalModule } from 'ngx-bootstrap/modal';  
  8. import { EmployeeDetailComponent } from './employee/employee-detail/employee-detail.component';  
  9. import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';  
  10.   
  11. @NgModule({  
  12.   declarations: [  
  13.     AppComponent  
  14.   ],  
  15.   imports: [  
  16.     ModalModule.forRoot(),  
  17.     BrowserModule,  
  18.     AppRoutingModule,  
  19.     EmployeeModule,  
  20.     BrowserAnimationsModule  
  21.   ],  
  22.   providers: [BsModalService, BsModalRef],  
  23.   schemas: [NO_ERRORS_SCHEMA],  
  24.   bootstrap: [AppComponent],  
  25.   entryComponents: [EmployeeDetailComponent]  
  26. })  
  27. export class AppModule { }  
 AppComponent.cs
  1. import { Component } from '@angular/core';  
  2.   
  3. @Component({  
  4.   selector: 'app-root',  
  5.   templateUrl: './app.component.html',  
  6.   styleUrls: ['./app.component.css']  
  7. })  
  8. export class AppComponent {  
  9.   title = 'test-employee-app';  
  10. }  
  AppModule.cs,
  1. <app-employee></app-employee>  
  EmployeeModule.cs,
  1. import { NgModule } from '@angular/core';  
  2. import { CommonModule } from '@angular/common';  
  3. import { EmployeeComponent } from './employee.component';  
  4. import { EmployeeDetailComponent } from './employee-detail/employee-detail.component';  
  5. import { EmployeeListComponent } from './employee-list/employee-list.component';  
  6.   
  7. @NgModule({  
  8.   declarations: [EmployeeComponent, EmployeeListComponent, EmployeeDetailComponent],  
  9.   imports: [  
  10.     CommonModule  
  11.   ],  
  12.   exports: [EmployeeComponent]  
  13. })  
  14. export class EmployeeModule { }  
  EmployeeComponent.ts,
  1. import { Component, OnInit } from '@angular/core';  
  2.   
  3. import { Employee } from '../shared/interfaces';  
  4. import { EmployeeDataService } from '../core/services/employeedata.service';  
  5.   
  6. @Component({  
  7.   selector: 'app-employee',  
  8.   templateUrl: './employee.component.html',  
  9.   styleUrls: ['./employee.component.css']  
  10. })  
  11. export class EmployeeComponent implements OnInit {  
  12.   
  13.   public employee: Employee;  
  14.   public employees: Employee[];  
  15.   
  16.   constructor(private employeeService: EmployeeDataService) { }  
  17.   
  18.   ngOnInit(): void {  
  19.     this.getEmployees();  
  20.   }  
  21.   
  22.   getEmployees() {  
  23.     this.employeeService.getEmployees()  
  24.     .subscribe((emps: Employee[]) => this.employees = emps);  
  25.   }    
  26.    selected(employee: any){  
  27.     this.employee = employee;  
  28.   }    
  29. }  
 Employeecomponent.html,
  1. <div class="row">  
  2.     <div class="col-md-6">  
  3.         <app-employee-list [employees]="employees" (employeeSelected)='selected($event)'></app-employee-list>  
  4.     </div>  
  5.     <!-- <div class="col-md-6">  
  6.         <app-employee-detail [employee]="employee"></app-employee-detail>         
  7.     </div> -->  
  8. </div>  
employee-list.component.ts,
  1. import { Component, OnInit, Input, ChangeDetectionStrategy, EventEmitter, Output } from '@angular/core';  
  2. import { Employee } from 'src/app/shared/interfaces';  
  3. import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';  
  4. import { EmployeeDetailComponent } from '../employee-detail/employee-detail.component';  
  5.   
  6. @Component({  
  7.   selector: 'app-employee-list',  
  8.   templateUrl: './employee-list.component.html',  
  9.   styleUrls: ['./employee-list.component.css'],  
  10.   changeDetection: ChangeDetectionStrategy.OnPush  
  11. })  
  12.   
  13. export class EmployeeListComponent implements OnInit {  
  14.   
  15. @Input() public employees: Employee[];  
  16. @Output() public employeeSelected = new EventEmitter<Employee>();  
  17. public bsModalRef: BsModalRef;  
  18.   
  19. constructor(private modalService: BsModalService) {}  
  20.   
  21.   ngOnInit(): void {  
  22.   }  
  23.   
  24.   selectEmployee(emp: Employee) {  
  25.     this.employeeSelected.emit(emp);  
  26.     const initialState = {  
  27.      employee: emp  
  28.     };  
  29.     this.bsModalRef = this.modalService.show(EmployeeDetailComponent, {initialState});  
  30.     this.bsModalRef.content.closeBtnName = 'Close';  
  31.   }    
  32. }  
employee-list.component.html,
  1. <h4>Employees</h4>  
  2. <table class="table table-striped">  
  3.   <tr>  
  4.     <th>Name</th>  
  5.     <th>Email</th>  
  6.   </tr>  
  7.   <tr *ngFor="let emp of employees" (click)="selectEmployee(emp)">  
  8.     <td>{{ emp.name }}</td>  
  9.     <td>{{ emp.email }}</td>  
  10.   </tr>  
  11. </table>  
  12. <br />  
 employee-detail.component.ts,
  1. import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core';  
  2. import { Employee } from 'src/app/shared/interfaces';  
  3. import { BsModalRef } from 'ngx-bootstrap/modal';  
  4.   
  5. @Component({  
  6.   selector: 'app-employee-detail',  
  7.   templateUrl: './employee-detail.component.html',  
  8.   styleUrls: ['./employee-detail.component.css'],  
  9.   changeDetection: ChangeDetectionStrategy.OnPush  
  10. })  
  11.   
  12. export class EmployeeDetailComponent implements OnInit {  
  13.   
  14. @Input() public employee: Employee;  
  15.   
  16. constructor(public bsModalRef: BsModalRef) { }  
  17.   
  18.   ngOnInit(): void {  
  19.   }    
  20. }  
 employee-detail.component.html,
  1. <div class="modal-header">  
  2.    <h4 class="modal-title pull-left">Employee Detail</h4>  
  3.    <button type="button" class="close pull-right" aria-label="Close" (click)="bsModalRef.hide()">  
  4.      <span aria-hidden="true">×</span>  
  5.    </button>  
  6.  </div>  
  7.  <div class="modal-body">  
  8.    Name: {{employee.name}}    
  9.    <br/>    
  10.    Email: {{employee.email}}    
  11.    <br/>  
  12.  </div>  
  13.  <div class="modal-footer">  
  14.    <button type="button" class="btn btn-default" (click)="bsModalRef.hide()">Close</button>  
  15.  </div>  

Summary

 
In this post, we learned about Container and Presentation component communication in Angular. Also, we added the modal popup child component.
 
To understand Container and Presentation components, please refer to the below post.