It is also possible to define a column in the TypeScript's component file.
DikeGrid Column API
In order to define a column in the TypeScript's component file, you must grab the corresponding column API of type DikeGridColumnDef from the DikeGridComponent instance you are defining columns.
There are two ways of grabbing this instance:
Querying the DikeGridComponent from the View
Every DikeGridComponent instance has its own DikeGridColumnDef instance. The instance is exposed as a public property called columnDef.
See the DikeGridComponent definition for a complete list of properties.
The following code snippet shows how the DikeGridComponent is retrieved and then, how Gender and Age columns are added using the column API.
import { AfterViewInit, Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
import { DikeGridComponent, DikeGridDataSourceInput, DikeBinaryColumnDef, DikeNumericColumnDef, DikeGridColumnDef, DikeTextColumnDef, DikeDateColumnDef} from'@dikesoft/angular-data-grid';import { Employee } from'app/mock-api/common/employees/data.model';import { SampleData } from'app/services/sample-data.service';@Component({ selector:'column-definitions', templateUrl:'./column-definitions.component.html', styleUrls: ['./column-definitions.component.scss'], encapsulation:ViewEncapsulation.None, changeDetection:ChangeDetectionStrategy.OnPush})exportclassColumnDefinitionsComponentimplementsOnInit,AfterViewInit {// Retrieve the DikeGridComponent<T> instance from the view: @ViewChild('grid') dikeGrid:DikeGridComponent<Employee>; dkgDataSource:DikeGridDataSourceInput<Employee>;constructor(private sampleData:SampleData) { }onColumnDefInstance(columnDef:DikeGridColumnDef<Employee>):void {// Define the Email column:constemailColumn=newDikeTextColumnDef<Employee>('email','Email');emailColumn.width =300;// Define the Hire Date column:consthireDateColumn=newDikeDateColumnDef<Employee>('hireDate','Hire Date');// Then, add the colums to the DikeGridComponent instance:columnDef.addColumns([ emailColumn, hireDateColumn ]); }ngOnInit():void {this.dkgDataSource =this.sampleData.getEmployees(1000); }ngAfterViewInit():void {// The DikeGridComponent<T> instance is available:Promise.resolve().then(() => {// Define the Gender column:constgenderColumn=newDikeBinaryColumnDef<Employee>('gender','Gender');genderColumn.width =110;// Define the Age column:constageColumn=newDikeNumericColumnDef<Employee>('age','Age');ageColumn.width =85;// Finally, add them to the DikeGridComponent<T> instance:this.dikeGrid.columnDef.addColumns([ genderColumn, ageColumn ]); }); }}
As you can see in the previous code snippet, the gridColumnDefInstance is attached to the onColumnDefInstance() method. In the method definition, two more columns were added: Email and Hire Date.
The gridColumnDefInstance event is emitted after the ngOnInit() lifecycle hook of the DikeGridComponent component.
The following screenshot shows the output after adding the columns:
By default, columns show a context menu. You can suppress this context menu for a specific column, all columns in a DikeGrid definition, or all DikeGrid instances.
Every column definition has an order property. If this property is not specified, the order of the columns depends on at which moment the columns are defined.
The following table shows the execution order the column definitions take place:
Column Definition
gridColumnDefInstance event listener
As it was told, this event is emitted after the ngOnInit() lifecycle hook of the DikeGridComponent component.
HTML definition
These columns are added in the ngAfterContentInit() lifecycle hook of the DikeGridComponent component.
DikeGridComponent instance queried from the view.
These columns are added in the ngAfterViewInit() lifecycle hook of the component that has the DikeGridComponent definition.
In every Column Definition execution, the columns are added in the order they are defined unless the order property is set.
Specifying the order of the columns
Let's say we want the following order:
Employee Id
Surname
Name
Gender
Age
Email
Hire Date
After setting the order property, the output will be the following:
Column types
Th DikeGrid Library defines four column types through a union type called DikeColumnDataType.
Depending on which type the column is, there is a default alignment used to display the content of the rows.
DikeColumnDataType
Inner Type / Default alignment
Class Definition
Text
It holds data of type string.
Default alignment start.
Instance of type DikeTextColumnDef.
Numeric
It holds data of type number.
Default alignment end.
Instance of type DikeNumericColumnDef.
Date
It hold data of type string, number, Date.
Default alignment center.
Instance of type DikeDateColumnDef.
Binary
It holds data of type string, number, boolean.
Default alignment center.
Instance of type DikeBinaryColumnDef.
Content alignment comes from a union type called ColumnAlignment. This alignment could be set overwriting the default value.
When a column is defined via templating, the type must be provided through the dataType input property. If the column is defined in code, the corresponding class instance must be created.
Retrieving and Updating a field value
By default, every column defines functions for getting or setting its field value. For instance, consider a Numeric column, its default getter function is:
These functions are of type GetterFn<T, R> and SetterFn<T, R> respectively. These default functions treat the received object of type T as a simple object, which means an object without any nested object.
Let's define the getter function for the Employee interface to retrieve the sales for March month.
// Define the March Sales column:constmarchSales=newDikeNumericColumnDef<Employee>('marchSales','March Sales');marchSales.width =150;marchSales.getValue= (entry:Employee):number=>entry.sales.monthlySales['March'];
The result of adding the column March Sales is shown in the following image:
As you can see, the marchSales field was defined but it does not exist. There is no marchSales field in the Employee interface, the value is in a nested object. Therefore, it is mandatory to define the getter function that retrieves the desired value.
If the column were editable, the corresponding setter function looks like the following:
Every column has a default template for displaying its field value. This template depends on the column type because depending on the type the corresponding Angular Pipe is applied.
Text and Binary columns
<!-- Template definition for Text columns -->
<ng-template #dikeTextDisplay let-entry="rowEntry" let-value="fieldValue">
<p>{{ value }}</p>
</ng-template>
<!-- Template definition for Binary columns -->
<ng-template #dikeBinaryDisplay let-entry="rowEntry" let-value="fieldValue">
<p>{{ value }}</p>
</ng-template>
As you can see, for Text and Binary columns no Angular Pipes are applied.
Numeric and Date columns
<!-- Template definition for Numeric columns -->
<ng-template #dikeNumericDisplay let-entry="rowEntry" let-value="fieldValue">
<p>{{ value | number }}</p>
</ng-template>
<!-- Template definition for Date columns -->
<ng-template #dikeDateDisplay let-entry="rowEntry" let-value="fieldValue">
<p>{{ value | date:'shortDate' }}</p>
</ng-template>
To see more on Angular pipes visit the official docs.
Custom templates
You can define your own templates. If you notice when defining a template you always have available the row entry and the field value. Let's define custom templates for Surname, Name, Gender, Hire Date, and March Sales.
Surname and Name templates
The uppercase Angular Pipe for Surname and Name column templates was added. These templates are bound in the HTML definition.
Both templates are assigned to the input property called displayTemplate.
Gender template
See the following code snippet for the Gender column template definition:
<!-- Gender column template is defined outside the dike-grid selector -->
<ng-template #gender let-value="fieldValue">
<mat-icon [matTooltip]="value">{{ value }}</mat-icon>
</ng-template>
@Component({ selector:'column-definitions', templateUrl:'./column-definitions.component.html', styleUrls: ['./column-definitions.component.scss'], encapsulation:ViewEncapsulation.None, changeDetection:ChangeDetectionStrategy.OnPush})exportclassColumnDefinitionsComponentimplementsOnInit,AfterViewInit {// Retrieve the corresponding template: @ViewChild('gender', { read: TemplateRef }) genderTpl:TemplateRef<any>;constructor(private sampleData:SampleData) { }ngAfterViewInit():void {// The DikeGridComponent<T> instance is available:Promise.resolve().then(() => {// Define the Gender column:constgenderColumn=newDikeBinaryColumnDef<Employee>('gender','Gender');genderColumn.width =110;genderColumn.order =4;// Since genderTpl is available in this life cycle hook, just assign the template:genderColumn.displayTemplate =this.genderTpl;// Define the Age column:constageColumn=newDikeNumericColumnDef<Employee>('age','Age');ageColumn.width =85;ageColumn.order =5;// Finally, add them to the DikeGridComponent<T> instance:this.dikeGrid.columnDef.addColumns([ genderColumn, ageColumn ]); }); }}
As you can see the Gender column template is retrieved querying the component's view. Remember that queried elements are set before the ngAfterViewInit life cycle hook, and the Gender column is defined in the ngAfterViewInit life cycle hook, the Gender column template is assigned to its corresponding column property.
Hire Date and March Sales column templates
In the following code snippet is shown the column templates definitions:
<!-- Column templates are defined outside the dike-grid selector -->
<ng-template #hireDate let-value="fieldValue">
<p>{{ value | date:'fullDate' }}</p>
</ng-template>
<ng-template #marchSales let-value="fieldValue">
<p>{{ value | currency }}</p>
</ng-template>
@Component({ selector:'column-definitions', templateUrl:'./column-definitions.component.html', styleUrls: ['./column-definitions.component.scss'], encapsulation:ViewEncapsulation.None, changeDetection:ChangeDetectionStrategy.OnPush})exportclassColumnDefinitionsComponentimplementsOnInit,AfterViewInit {// Retrieve the corresponding template: @ViewChild('hireDate', { read: TemplateRef }) hireDateTpl:TemplateRef<any>; @ViewChild('marchSales', { read: TemplateRef }) marchSalesTpl:TemplateRef<any>;constructor(private sampleData:SampleData) { }onColumnDefInstance(columnDef:DikeGridColumnDef<Employee>):void {// Define the Email column:constemailColumn=newDikeTextColumnDef<Employee>('email','Email');emailColumn.width =300;emailColumn.order =6;// Define the Hire Date column:consthireDateColumn=newDikeDateColumnDef<Employee>('hireDate','Hire Date');hireDateColumn.order =7;hireDateColumn.width =215;hireDateColumn.displayTemplate =from(Promise.resolve().then(() =>this.hireDateTpl));// Define the March Sales column:constmarchSales=newDikeNumericColumnDef<Employee>('marchSales','March Sales');marchSales.order =8;marchSales.width =150;marchSales.getValue= (entry:Employee):number=>entry.sales.monthlySales['March'];/** * Since Hire Date and March Sales columns are defined before the templates are ready * and available, an Observable is assigned waiting for the template availability. */marchSales.displayTemplate =from(Promise.resolve().then(() =>this.marchSalesTpl));// Then, add the colums to the DikeGridComponent instance:columnDef.addColumns([ emailColumn, hireDateColumn, marchSales ]); }}
For Hire Date and March Sales column templates, the date and currency Angular Pipes are used respectively.
For these columns, an Observable is assigned to displayTemplate column property because both columns are defined in the gridColumnDefInstance event callback. Column templates will be available until the ngAfterViewInit hook and, remember that the gridColumnDefInstance event is emitted just after the DikeGridComponent'sngOnInit hook.
The following screenshot shows the output after defining the custom templates.
Column Identifiers
All column identifiers are UUIDs and are used internally. If the user assigns them when defining columns, these are ignored.
The column identifiers are columnId, slotId and belongToGroup properties.
Summary
In this section, the main building blocks were covered. Columns are the main part for displaying data through a DikeGrid instance.
import { AfterViewInit, Component, OnInit, ViewChild, TemplateRef, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
import { from } from'rxjs';import { DikeGridComponent, DikeGridDataSourceInput, DikeBinaryColumnDef, DikeNumericColumnDef, DikeGridColumnDef, DikeTextColumnDef, DikeDateColumnDef} from'@dikesoft/angular-data-grid';import { Employee } from'app/mock-api/common/employees/data.model';import { SampleData } from'app/services/sample-data.service';@Component({ selector:'column-definitions', templateUrl:'./column-definitions.component.html', styleUrls: ['./column-definitions.component.scss'], encapsulation:ViewEncapsulation.None, changeDetection:ChangeDetectionStrategy.OnPush})exportclassColumnDefinitionsComponentimplementsOnInit,AfterViewInit {// Retrieve the DikeGridComponent<T> instance from the view: @ViewChild('grid') dikeGrid:DikeGridComponent<Employee>;// Retrieve the corresponding template: @ViewChild('gender', { read: TemplateRef }) genderTpl:TemplateRef<any>; @ViewChild('hireDate', { read: TemplateRef }) hireDateTpl:TemplateRef<any>; @ViewChild('marchSales', { read: TemplateRef }) marchSalesTpl:TemplateRef<any>; dkgDataSource:DikeGridDataSourceInput<Employee>;constructor(private sampleData:SampleData) { }onColumnDefInstance(columnDef:DikeGridColumnDef<Employee>):void {// Define the Email column:constemailColumn=newDikeTextColumnDef<Employee>('email','Email');emailColumn.width =300;emailColumn.order =6;// Define the Hire Date column:consthireDateColumn=newDikeDateColumnDef<Employee>('hireDate','Hire Date');hireDateColumn.order =7;hireDateColumn.width =215;hireDateColumn.displayTemplate =from(Promise.resolve().then(() =>this.hireDateTpl));// Define the March Sales column:constmarchSales=newDikeNumericColumnDef<Employee>('marchSales','March Sales');marchSales.order =8;marchSales.width =150;marchSales.getValue= (entry:Employee):number=>entry.sales.monthlySales['March'];/** * Since Hire Date and March Sales columns are defined before the templates are ready * and available, an Observable is assigned waiting for the template availability. */marchSales.displayTemplate =from(Promise.resolve().then(() =>this.marchSalesTpl));// Then, add the colums to the DikeGridComponent instance:columnDef.addColumns([ emailColumn, hireDateColumn, marchSales ]); }ngOnInit():void {this.dkgDataSource =this.sampleData.getEmployees(1000); }ngAfterViewInit():void {// The DikeGridComponent<T> instance is available:Promise.resolve().then(() => {// Define the Gender column:constgenderColumn=newDikeBinaryColumnDef<Employee>('gender','Gender');genderColumn.width =110;genderColumn.order =4;// Since genderTpl is available in this life cycle hook, just assign the template:genderColumn.displayTemplate =this.genderTpl;// Define the Age column:constageColumn=newDikeNumericColumnDef<Employee>('age','Age');ageColumn.width =85;ageColumn.order =5;// Finally, add them to the DikeGridComponent<T> instance:this.dikeGrid.columnDef.addColumns([ genderColumn, ageColumn ]); }); }}