Editing Edition templates This section describes how to provide custom templates for editing the column values.
Live example
Default templates
It is enough to make a column editable to modify the column value. The DikeGrid instance will display the default templates depending on the column type. See the following table.
Column type
Default template
A Material Form field with an input element with type equals text
.
A Material Form field with an input element with type equals number
.
A Material Form field with a Material Datepicker inside.
Let us make some columns editable:
edition-templates.component.html
Copy <dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid"
allowEdition
[editionMode]="gridProperties.editionMode">
<dike-grid-column
fieldName="employeeId"
headerText="Employee Id"
dataType="Text"
width="350">
</dike-grid-column>
<dike-grid-column
fieldName="completeNameGroup"
headerText="Complete Name">
<dike-grid-column
fieldName="firstName"
headerText="Name"
dataType="Text"
width="150"
editable>
</dike-grid-column>
<dike-grid-column
fieldName="lastName"
headerText="Surname"
dataType="Text"
width="150"
editable>
</dike-grid-column>
</dike-grid-column>
<dike-grid-column
fieldName="gender"
headerText="Gender"
dataType="Binary"
width="110"
editable>
</dike-grid-column>
<dike-grid-column
fieldName="age"
headerText="Age"
dataType="Numeric"
contentAlign="center"
width="100"
editable>
</dike-grid-column>
<dike-grid-column
fieldName="email"
headerText="Email"
dataType="Text"
width="300"
editable>
</dike-grid-column>
<dike-grid-column
fieldName="hireDate"
headerText="Hire Date"
dataType="Date"
editable>
</dike-grid-column>
</dike-grid>
The previous initial configuration generates the following output:
In general, the default templates achieve the edition operations well. However, the problem arises with the Binary
columns when these do not hold boolean values.
As you can see, our Gender column values are female
and male
. Therefore, those values do not match in a checkbox.
Before providing our custom templates, let us explore a slight variation in default templates.
Multiple Selection
Sometimes, you want the user to choose a value from a fixed number of options.
To achieve the previous task, you can provide an array of options to the default template. The DikeGrid instance will create a template with a Material Select-control inside a Form field.
You must provide a set of options depending on the column type:
DikeNumericSelectionModel
Let us provide options to our Gender and Age default templates.
edition-templates.component.html edition-templates.component.ts
Copy <dike-grid-column
fieldName="gender"
headerText="Gender"
dataType="Binary"
width="110"
editable
[editionSettings]="{ required: true, options: [ { label: 'M', value: 'male' }, { label: 'F', value: 'female' } ] }">
</dike-grid-column>
<dike-grid-column
fieldName="age"
headerText="Age"
dataType="Numeric"
contentAlign="center"
width="100"
editable
[editionSettings]="{ options: ageOptions }">
</dike-grid-column>
Copy @Component({
selector: 'edition-templates',
templateUrl: './edition-templates.component.html',
styleUrls: ['./edition-templates.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditionTemplatesComponent implements OnInit, OnDestroy {
ageOptions: DikeNumericSelectionModel[];
ngOnInit(): void {
//...
// Define mutiple options for the Age column:
this.ageOptions = [
{ label: '27', value: 27 },
{ label: '36', value: 36 },
{ label: '40', value: 40 },
{ label: '42', value: 42 },
{ label: '43', value: 43 },
{ label: '50', value: 50 },
{ label: '52', value: 52 },
{ label: '53', value: 53 }
];
}
}
For Binary
columns, the DikeGrid will take the first two options of the provided set. The DikeGrid will ignore the other options if you offer more than two options.
For Text
and Numeric
columns, you can provide any number of options.
Custom templates
You can provide your custom templates if you need a more specific template for editing your column values.
See the following custom templates:
edition-templates.component.html edition-templates.component.ts
Copy <dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid"
(gridColumnDefInstance)="onColumnDefInstance($event)">
<dike-grid-column
fieldName="gender"
headerText="Gender"
dataType="Binary"
width="110"
editable
[editionSettings]="{ required: true, options: [ { label: 'M', value: 'male' }, { label: 'F', value: 'female' } ] }"
[editionTemplate]="genderEdition">
</dike-grid-column>
<dike-grid-column
fieldName="email"
headerText="Email"
dataType="Text"
width="300"
editable
[editionTemplate]="emailEdition">
</dike-grid-column>
</dike-grid>
<ng-template #genderEdition let-control="control" let-options="options">
<mat-radio-group class="flex flex-row justify-between" [formControl]="control">
<mat-radio-button *ngFor="let option of options" [value]="option.value">{{ option.label }}</mat-radio-button>
</mat-radio-group>
</ng-template>
<ng-template #emailEdition let-control="control">
<mat-form-field floatLabel="never">
<input matInput
type="text"
[formControl]="control"
autocomplete="off">
<mat-icon matSuffix>email</mat-icon>
</mat-form-field>
</ng-template>
<ng-template #totalSales let-value="fieldValue">
<p>{{ value | currency }}</p>
</ng-template>
<ng-template #totalSalesEdition let-control="control">
<mat-form-field floatLabel="never">
<input matInput
type="number"
[formControl]="control"
autocomplete="off">
<mat-icon matPrefix>attach_money</mat-icon>
</mat-form-field>
</ng-template>
Copy @Component({
selector: 'edition-templates',
templateUrl: './edition-templates.component.html',
styleUrls: ['./edition-templates.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditionTemplatesComponent implements OnInit, OnDestroy {
// Retrieve the Total sales templates:
@ViewChild('totalSales', { read: TemplateRef }) totalSalesTpl: TemplateRef<any>;
@ViewChild('totalSalesEdition', { read: TemplateRef }) totalSalesEditionTpl: TemplateRef<any>;
//...
onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
// Define the Total Sales column:
const totalSalesColumn = new DikeNumericColumnDef<Employee>('totalSales', 'Total Sales');
totalSalesColumn.width = 230;
totalSalesColumn.order = 7;
totalSalesColumn.editable = true;
totalSalesColumn.editionSettings = { required: true };
// Since templates will be available after the view is initialized, we schedule the assignment at the end of the event loop:
totalSalesColumn.displayTemplate = from(Promise.resolve().then(() => this.totalSalesTpl));
totalSalesColumn.editionTemplate = from(Promise.resolve().then(() => this.totalSalesEditionTpl));
columnDef.addColumns(totalSalesColumn);
}
}
We have defined templates for the Gender , Email , and Total Sales columns.
We take the options we set to the default template to provide them to our custom template for the Gender column.
We intentionally defined the Total Sales column in the code. See how we assign the template.
You will have access to the corresponding FormControl
and the options provided in the EditionFieldSettings
object.
The editionTemplate
and displayTemplate
properties accept a TemplateRef
or an Observable
of a TemplateRef
.
Assigning a template using the API
You can assign a custom template to a column or set the default template again.
Before using the API, we have to retrieve the DikeGrid instance from the component's view.
edition-templates.component.html edition-templates.component.ts
Copy <dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid">
</dike-grid>
Copy @Component({
selector: 'edition-templates',
templateUrl: './edition-templates.component.html',
styleUrls: ['./edition-templates.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditionTemplatesComponent implements OnInit, OnDestroy {
// Retrieve the DikeGridComponent<T> instance from the view:
@ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;
//...
}
DikeGrid Column API
You can set edition templates at runtime using the column API .
The methods regarding edition templates are:
Use this method to set the edition template to the given column.
setDefaultEditionTemplateColumn()
You can establish the default edition template for the given column again.
To see the API in action, consider the following configuration:
edition-templates.component.html edition-templates.component.ts
Copy <div class="mt-2 flex flex-row flex-wrap items-center justify-around">
<div class="flex-none w-56 flex flex-col m-2 items-center">
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onDefaultTemplate('gender')">Gender default template
</button>
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onCustomTemplate('gender')">Gender custom template
</button>
</div>
<div class="flex-none w-56 flex flex-col m-2 items-center">
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onDefaultTemplate('email')">Email default template
</button>
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onCustomTemplate('email')">Email custom template
</button>
</div>
</div>
<dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid">
</dike-grid>
Copy @Component({
selector: 'edition-templates',
templateUrl: './edition-templates.component.html',
styleUrls: ['./edition-templates.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditionTemplatesComponent implements OnInit, OnDestroy {
// Retrieve the DikeGridComponent<T> instance from the view:
@ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;
// Retrieve the Total sales templates:
@ViewChild('genderEdition', { read: TemplateRef }) genderEditionTpl: TemplateRef<any>;
@ViewChild('emailEdition', { read: TemplateRef }) emailEditionTpl: TemplateRef<any>;
//...
onCustomTemplate(field: string): void {
const givenColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === field);
// The column exists and is a data column:
if (!!givenColumn && isDikeDataColumnDef(givenColumn)) {
// Get the custom edition template:
const columnTemplate = field === 'gender' ? this.genderEditionTpl : this.emailEditionTpl;
// Assign the custom template for the given column:
this.dikeGrid.columnDef.setColumnEditable(givenColumn, true, { editionTemplate: columnTemplate });
}
}
onDefaultTemplate(field: string): void {
const givenColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === field);
// The column exists and is a data column:
if (!!givenColumn && isDikeDataColumnDef(givenColumn)) {
this.dikeGrid.columnDef.setDefaultEditionTemplateColumn(givenColumn);
}
}
}
The previous definition generates the following output:
We have added four buttons:
Gender default template . When you click on this button, you will set the default template again.
Gender custom template . This action will assign the custom edition template.
Email default template . It will establish the default edition template.
Email custom template . You will set the custom edition template when you click on this button.
As you can see, when changing the template, the DikeGrid re-renders the view for that column.
Summary
The DikeGrid definition offers you a default template for each column type. Nonetheless, you can provide custom edition templates when defining a column or using the API.
Complete code for this section.
edition-templates.component.html edition-templates.component.ts
Copy <div class="mt-2 flex flex-row flex-wrap items-center justify-around">
<div class="flex-none w-56 flex flex-col m-2 items-center">
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onDefaultTemplate('gender')">Gender default template
</button>
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onCustomTemplate('gender')">Gender custom template
</button>
</div>
<div class="flex-none w-56 flex flex-col m-2 items-center">
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onDefaultTemplate('email')">Email default template
</button>
<button mat-raised-button
class="flex-none w-56 my-2"
color="primary"
(click)="onCustomTemplate('email')">Email custom template
</button>
</div>
</div>
<dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid"
[displayRowId]="gridProperties.displayRowId"
[gridElevation]="gridProperties.matElevation"
[gridElevationValue]="gridProperties.elevationValue"
[striped]="gridProperties.stripeRows"
[verticalRowLines]="gridProperties.verticalRowLines"
allowEdition
[editionMode]="gridProperties.editionMode"
(gridColumnDefInstance)="onColumnDefInstance($event)"
[datasource]="dkgDataSource">
<dike-grid-column
fieldName="employeeId"
headerText="Employee Id"
dataType="Text"
width="350">
</dike-grid-column>
<dike-grid-column
fieldName="completeNameGroup"
headerText="Complete Name">
<dike-grid-column
fieldName="firstName"
headerText="Name"
dataType="Text"
width="150"
editable>
</dike-grid-column>
<dike-grid-column
fieldName="lastName"
headerText="Surname"
dataType="Text"
width="150"
editable>
</dike-grid-column>
</dike-grid-column>
<dike-grid-column
fieldName="gender"
headerText="Gender"
dataType="Binary"
width="110"
editable
[editionSettings]="{ required: true, options: [ { label: 'M', value: 'male' }, { label: 'F', value: 'female' } ] }"
[editionTemplate]="genderEdition">
</dike-grid-column>
<dike-grid-column
fieldName="age"
headerText="Age"
dataType="Numeric"
contentAlign="center"
width="100"
editable
[editionSettings]="{ options: ageOptions }">
</dike-grid-column>
<dike-grid-column
fieldName="email"
headerText="Email"
dataType="Text"
width="300"
editable
[editionTemplate]="emailEdition">
</dike-grid-column>
<dike-grid-column
fieldName="hireDate"
headerText="Hire Date"
dataType="Date"
editable>
</dike-grid-column>
</dike-grid>
<ng-template #genderEdition let-control="control" let-options="options">
<mat-radio-group class="flex flex-row justify-between" [formControl]="control">
<mat-radio-button *ngFor="let option of options" [value]="option.value">{{ option.label }}</mat-radio-button>
</mat-radio-group>
</ng-template>
<ng-template #emailEdition let-control="control">
<mat-form-field floatLabel="never">
<input matInput
type="text"
[formControl]="control"
autocomplete="off">
<mat-icon matSuffix>email</mat-icon>
</mat-form-field>
</ng-template>
<ng-template #totalSales let-value="fieldValue">
<p>{{ value | currency }}</p>
</ng-template>
<ng-template #totalSalesEdition let-control="control">
<mat-form-field floatLabel="never">
<input matInput
type="number"
[formControl]="control"
autocomplete="off">
<mat-icon matPrefix>attach_money</mat-icon>
</mat-form-field>
</ng-template>
Copy import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { from, Subscription } from 'rxjs';
import { DikeGridColumnDef, DikeGridComponent, DikeGridDataSourceInput,
DikeNumericColumnDef, DikeNumericSelectionModel, isDikeDataColumnDef
} from '@dikesoft/angular-data-grid';
import { DikeGridProperties } from 'app/core/config/dike-grid.properties';
import { Employee } from 'app/mock-api/common/employees/data.model';
import { SampleData } from 'app/services/sample-data.service';
import { DikeGridConfig } from 'app/services/dike-grid.config.service';
@Component({
selector: 'edition-templates',
templateUrl: './edition-templates.component.html',
styleUrls: ['./edition-templates.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditionTemplatesComponent implements OnInit, OnDestroy {
// Retrieve the DikeGridComponent<T> instance from the view:
@ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;
// Retrieve the Total sales templates:
@ViewChild('totalSales', { read: TemplateRef }) totalSalesTpl: TemplateRef<any>;
@ViewChild('totalSalesEdition', { read: TemplateRef }) totalSalesEditionTpl: TemplateRef<any>;
@ViewChild('genderEdition', { read: TemplateRef }) genderEditionTpl: TemplateRef<any>;
@ViewChild('emailEdition', { read: TemplateRef }) emailEditionTpl: TemplateRef<any>;
dkgDataSource: DikeGridDataSourceInput<Employee>;
gridProperties: DikeGridProperties;
ageOptions: DikeNumericSelectionModel[];
private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;
constructor(
private cdr: ChangeDetectorRef,
private gridConfig: DikeGridConfig,
private sampleData: SampleData) { }
onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
// Define the Total Sales column:
const totalSalesColumn = new DikeNumericColumnDef<Employee>('totalSales', 'Total Sales');
totalSalesColumn.width = 230;
totalSalesColumn.order = 7;
totalSalesColumn.editable = true;
totalSalesColumn.editionSettings = { required: true };
// Since templates will be available after the view is initialized, we schedule the assignment at the end of the event loop:
totalSalesColumn.displayTemplate = from(Promise.resolve().then(() => this.totalSalesTpl));
totalSalesColumn.editionTemplate = from(Promise.resolve().then(() => this.totalSalesEditionTpl));
columnDef.addColumns(totalSalesColumn);
}
ngOnInit(): void {
// Get 1000 entries from the REST API:
this.dkgDataSource = this.sampleData.getEmployees(1000);
// Listening to any config property change:
this.setChangeGridPropertiesSubscription();
// Define mutiple options for the Age column:
this.ageOptions = [
{ label: '27', value: 27 },
{ label: '36', value: 36 },
{ label: '40', value: 40 },
{ label: '42', value: 42 },
{ label: '43', value: 43 },
{ label: '50', value: 50 },
{ label: '52', value: 52 },
{ label: '53', value: 53 }
];
}
ngOnDestroy(): void {
this.changeGridPropertiesSubscription.unsubscribe();
}
onCustomTemplate(field: string): void {
const givenColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === field);
// The column exists and is a data column:
if (!!givenColumn && isDikeDataColumnDef(givenColumn)) {
// Get the custom edition template:
const columnTemplate = field === 'gender' ? this.genderEditionTpl : this.emailEditionTpl;
// Assign the custom template for the given column:
this.dikeGrid.columnDef.setColumnEditable(givenColumn, true, { editionTemplate: columnTemplate });
}
}
onDefaultTemplate(field: string): void {
const givenColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === field);
// The column exists and is a data column:
if (!!givenColumn && isDikeDataColumnDef(givenColumn)) {
this.dikeGrid.columnDef.setDefaultEditionTemplateColumn(givenColumn);
}
}
private setChangeGridPropertiesSubscription(): void {
this.changeGridPropertiesSubscription.unsubscribe();
this.changeGridPropertiesSubscription = this.gridConfig.configChange.subscribe((props: DikeGridProperties) => {
this.gridProperties = props;
this.cdr.markForCheck();
});
}
}