AngularJS 2.0 From Beginning - Dynamic Grid (Day 10)

I am here to continue the discussion around AngularJS 2.0. So far, we have discussed data binding, input properties, output properties, pipes, viewchild, and also directives in Angular 2.0. Now, in this article, I will discuss how to create a custom component like dynamic Grid using all the features which we discuss till now. Also, in case you did not have a look at the previous articles of this series, go through the links mentioned below.

In this Angular 2 article series, we have already discussed basic components and directives concepts in Angular2. Now in this article, I will show you how to create custom components, such as records that display dynamic Grids for using the concept of directives, pipes, and other features of Angular 2.

Now, for creating the dynamic Grid, we first need to create a custom component which will represent the dynamic Grid components. For this purpose, we first add the TypeScript file named app.component.dynamicgrid.ts file and add the below code. 

  1. import { Component, OnInit, Input, Output } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'dynamic-grid',  
  6.     templateUrl: 'app.component.dynamicgrid.html'  
  7. })  
  8.   
  9. export class DynamicGridComponent implements OnInit {  
  10.   
  11.     private _source: Array<any> = new Array<any>();  
  12.   
  13.     @Input() private columns: Array<columnDef> = new Array<columnDef>();  
  14.   
  15.     constructor() { }  
  16.   
  17.     ngOnInit(): void {  
  18.         if (this.columns == null || this.columns == undefined) {  
  19.             alert("Column Definition of grid not provided.");  
  20.             return;  
  21.         }  
  22.     }  
  23.   
  24.     public bindData(data: Array<any>): void {  
  25.         if (data != null && data != undefined) {  
  26.             this._source = data;  
  27.         }  
  28.     }  
  29.   
  30.     public clearGrid(): void {  
  31.         this._source = [];  
  32.     }  
  33. }  
  34.   
  35. export class columnDef {  
  36.     caption: string;  
  37.     dataField: string;  
  38.     dataType: columnDataType;  
  39.     width: string;  
  40.     display: boolean = true;  
  41. }  
  42.   
  43. export enum columnDataType {  
  44.     Text,  
  45.     Number,  
  46.     Datetime,  
  47.     Integer,  
  48. }  
In the above component, we created one Input Property, named columns, which is basically used for defining the column details such as caption and data field of the Grid columns. Also, we created two public methods within the Grid component called bindData() and clearGrid(). First function is used for binding data into the Grid component. This function takes an array type argument as data. The second method is used for clearing the Grid content.
 
In the above TypeScript file, we also defined two another classes named columnDef and columnDataType. These two classes are basically enum type classes which can be used for defining the column structure of the dynamic Grid component from the parent component.
 
Now, add an HTML file for dynamic Grid component templates named app.component.dynamicgrid.html and add the below code.
  1. <div class="ibox-content">  
  2.     <div class="ibox-table">  
  3.         <div class="table-responsive">  
  4.             <table class="responsive-table table-striped table-bordered table-hover">  
  5.                 <thead>  
  6.                     <tr>  
  7.                         <th *ngFor="let header of columns;let ind=index" [ngStyle]="{'width': header.width}">  
  8.                             <span>  
  9.                                 {{header.caption}}  
  10.                             </span>  
  11.                         </th>  
  12.                     </tr>  
  13.                 </thead>  
  14.                 <tbody>  
  15.                     <tr *ngFor="let s of _source; let i=index">  
  16.                         <td *ngFor="let cols of columns; let ind1=index" [ngSwitch]="cols.dataType" [ngStyle]="{'width': cols.width}">  
  17.                             <span *ngSwitchCase="0">  
  18.                                 {{s[cols.dataField]}}  
  19.                             </span>                             
  20.                             <span *ngSwitchCase="1">  
  21.                                 {{s[cols.dataField]}}  
  22.                             </span>  
  23.                             <span *ngSwitchCase="2">  
  24.                                 {{s[cols.dataField] | date:"fullDate"}}  
  25.                             </span>  
  26.                             <span *ngSwitchCase="3">  
  27.                                 {{s[cols.dataField]}}  
  28.                             </span>  
  29.                         </td>  
  30.                     </tr>  
  31.                 </tbody>  
  32.             </table>  
  33.         </div>  
  34.     </div>  
  35. </div>  
In the above code, we used ngFor and ngSwitch for populating the dynamic table columns. Also, we used date pipes for date field value formatting.
 
Now, we need to create another component within which we use these dynamic Grid components. Actually, this contains an entry form and also the dynamic Grid component. For this purpose, we first create an HTML file named app.component.gridsetting.html and add the below code.
  1. <div>  
  2.     <fieldset>  
  3.         <legend>  
  4.             Employee Information  
  5.         </legend>  
  6.         <table style="width:100%;">  
  7.             <tr>  
  8.                 <th>Employee Name</th>  
  9.                 <td><input type="text" maxlength="100" [(ngModel)]="_modelData.employeeName" /></td>  
  10.             </tr>  
  11.             <tr>  
  12.                 <th>Department</th>  
  13.                 <td><input type="text" maxlength="100"  [(ngModel)]="_modelData.department"/></td>  
  14.             </tr>  
  15.             <tr>  
  16.                 <th>Designation</th>  
  17.                 <td><input type="text" maxlength="100" [(ngModel)]="_modelData.designation" /></td>  
  18.             </tr>  
  19.             <tr>  
  20.                 <th>Date of Join</th>  
  21.                 <td><input type="date"  [(ngModel)]="_modelData.doj"/></td>  
  22.             </tr>  
  23.             <tr>  
  24.                 <th>Salary</th>  
  25.                 <td><input type="number"  [(ngModel)]="_modelData.salary"/></td>  
  26.             </tr>  
  27.             <tr>  
  28.                 <td style="text-align:right;"></td>  
  29.                 <td>  
  30.                     <input type="button" value="Add" (click)="addData();" />  
  31.                         
  32.                     <input type="button" value="Clear" (click)="clearData()" />  
  33.                         
  34.                     <input type="button" value="Reset Grid" (click)="resetGrid()" />  
  35.                 </td>  
  36.             </tr>  
  37.         </table>  
  38.     </fieldset>  
  39. </div>  
  40. <div>  
  41.     <h2>Employee Details</h2>  
  42.     <dynamic-grid [columns]="_columnDetails" #grid></dynamic-grid>  
  43. </div>  
Now, add a TypeScript file named app.component.gridsetting.ts and add the below code.
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2. import { DynamicGridComponent, columnDef, columnDataType } from './app.component.dynamicgrid';  
  3.   
  4. @Component({  
  5.     moduleId: module.id,  
  6.     selector: 'grid-setting',  
  7.     templateUrl: 'app.component.gridsetting.html'  
  8. })  
  9.   
  10. export class GridSettingComponent implements OnInit {  
  11.     private _columnDetails: Array<columnDef>;  
  12.     private _modelData: any = {};  
  13.     private _gridData: Array<any> = new Array<any>();  
  14.     private _srlNo: number;  
  15.   
  16.     @ViewChild('grid'private _gridComponent: DynamicGridComponent;  
  17.   
  18.     constructor() {  
  19.         this._columnDetails = [  
  20.             { caption: 'Srl No', dataField: 'srlNo', dataType: columnDataType.Integer, width: '10%', display: true },  
  21.             { caption: 'Employee Name', dataField: 'employeeName', dataType: columnDataType.Text, width: '30%', display: true },  
  22.             { caption: 'Departmentr', dataField: 'department', dataType: columnDataType.Text, width: '15%', display: true },  
  23.             { caption: 'Designation', dataField: 'designation', dataType: columnDataType.Text, width: '15%', display: true },  
  24.             { caption: 'Date Of Join', dataField: 'doj', dataType: columnDataType.Datetime, width: '15%', display: true },  
  25.             { caption: 'Salary', dataField: 'salary', dataType: columnDataType.Number, width: '15%', display: true }];  
  26.     }  
  27.   
  28.     ngOnInit(): void {  
  29.         this._srlNo = 1;  
  30.     }  
  31.   
  32.     private addData(): void {  
  33.         if (this.validateData()) {  
  34.             this._modelData.srlNo = this._srlNo;  
  35.             this._srlNo += 1;  
  36.             this._modelData.doj = new Date(this._modelData.doj);  
  37.             this._gridData.push(this._modelData);  
  38.             this.clearData();  
  39.             this._gridComponent.bindData(this._gridData);  
  40.         }  
  41.     }  
  42.   
  43.     private clearData(): void {  
  44.         this._modelData = {};  
  45.     }  
  46.   
  47.     private validateData(): boolean {  
  48.         let status = true;  
  49.         if (this.isUndefined(this._modelData.employeeName)) {  
  50.             alert('Employee Name never blank');  
  51.             status = false;  
  52.         }  
  53.         else if (this.isUndefined(this._modelData.department)) {  
  54.             alert('Department never blank');  
  55.             status = false;  
  56.         }  
  57.         else if (this.isUndefined(this._modelData.designation)) {  
  58.             alert('Designation never blank');  
  59.             status = false;  
  60.         }  
  61.         else if (this.isUndefined(this._modelData.salary)) {  
  62.             alert('Salary never blank');  
  63.             status = false;  
  64.         }  
  65.         else if (this.isUndefined(this._modelData.doj)) {  
  66.             alert('Date of Join never blank');  
  67.             status = false;  
  68.         }  
  69.         return status;  
  70.     }  
  71.   
  72.     private isUndefined(data: any): boolean {  
  73.         return typeof (data) === "undefined";  
  74.     }  
  75.   
  76.     private resetGrid(): void {  
  77.         this._gridData = [];  
  78.         this._modelData = {};  
  79.         this._gridComponent.clearGrid();  
  80.     }  
  81. }  
In the above component, for accessing the public method of the Grid component, we use viewchild concept. Now, add another TypeScript file named app.module.ts and write down the below code.
  1. import { NgModule } from '@angular/core';  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3. import { FormsModule } from "@angular/forms";  
  4. import { GridSettingComponent } from './src/app.component.gridsetting';  
  5. import { DynamicGridComponent } from './src/app.component.dynamicgrid';  
  6.   
  7. @NgModule({  
  8.     imports: [BrowserModule, FormsModule],  
  9.     declarations: [GridSettingComponent, DynamicGridComponent],  
  10.     bootstrap: [GridSettingComponent]  
  11. })  
  12. export class AppModule { }  
Now, add another TypeScript file named main.ts and add the below code.
  1. import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';  
  2.   
  3. import { AppModule } from './app.module';  
  4.   
  5. const platform = platformBrowserDynamic();  
  6. platform.bootstrapModule(AppModule);  
Now, add another HTML file named index.html and add the below code.
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>Angular2 - Custom Grid</title>  
  5.     <meta charset="UTF-8">  
  6.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  7.     <link href="../resources/style/style1.css" rel="stylesheet" />  
  8.     <!-- Polyfill(s) for older browsers -->  
  9.     <script src="../node_modules/core-js/client/shim.min.js"></script>  
  10.     <script src="../node_modules/zone.js/dist/zone.js"></script>  
  11.     <script src="../node_modules/reflect-metadata/Reflect.js"></script>  
  12.     <script src="../node_modules/systemjs/dist/system.src.js"></script>  
  13.     <script src="../systemjs.config.js"></script>  
  14.     <script>  
  15.         System.import('app').catch(function (err) { console.error(err); });  
  16.     </script>  
  17. </head>  
  18. <body>  
  19.     <grid-setting>Loading</grid-setting>  
  20.       
  21. </body>  
  22. </html>  
Now, run the code. The output is shown below.