DkGrid
  • Overview
  • Getting Started
    • Quick Start Tutorial
  • Fundamentals
    • Grid Structure
      • Grid Size
      • Header
      • Row Filter
      • Rows
      • Panels
      • Gutters
      • Edition Toolbar
      • Paginator
      • Borders
      • Column Context Menu
      • Waiting Indicator
    • DataSource
      • In-Memory DataSource
      • Custom DataSource
    • Theming
  • Columns
    • Column Definitions
    • Column Grouping
    • Column Sizing
    • Column Moving
    • Column Pinning
  • Rows
    • Row Sorting
    • Row Selection
    • Row Grouping
    • Row Pagination
  • Filtering
    • Column Filters
    • Filter types
    • In-line Filters
  • Editing
    • Row Edition
    • Edition templates
    • Edition validation
    • Multiple rows edition
  • Reference
    • DkGrid API
      • DkGridColumnDef
      • DkGridSorting
      • DkGridSelection
      • DkGridRowGrouping
      • DkGridPagination
      • DkGridWaitingIndicator
      • DkGridFactoryDataSource
      • DkGridFilter
      • DkGridEdition
    • Components
      • DkGridComponent
      • DkGridColumnComponent
    • Classes
      • DataSource
      • Columns
      • Rows
      • Filtering
      • Editing
    • Interfaces
      • Columns
      • Sorting
      • Row Grouping
      • Filtering
      • Editing
    • Injection Tokens
      • Grid Structure
      • Filtering
      • Editing
      • Theming
    • Type aliases
      • DataSource
      • Columns
      • Selection
      • Filtering
      • Editing
    • Type Guards
Powered by GitBook
On this page
  • Live example
  • Default templates
  • Multiple Selection
  • Custom templates
  • Assigning a template using the API
  • DikeGrid Column API
  • Summary
  • Complete code for this section.
  1. Editing

Edition templates

This section describes how to provide custom templates for editing the column values.

PreviousRow EditionNextEdition validation

Last updated 2 years ago

Live example

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

Text

A Material Form field with an input element with type equals text.

Numeric

A Material Form field with an input element with type equals number.

Date

A Material Form field with a Material Datepicker inside.

Binary

A Material checkbox.

Let us make some columns editable:

edition-templates.component.html
<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:

Column type
Array type

Text

DikeTextSelectionModel

Numeric

DikeNumericSelectionModel

Binary

DikeBinarySelectionModel

Let us provide options to our Gender and Age default templates.

<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>
@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:

<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>
@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);
  }
}
  1. We have defined templates for the Gender, Email, and Total Sales columns.

  2. We take the options we set to the default template to provide them to our custom template for the Gender column.

  3. We intentionally defined the Total Sales column in the code. See how we assign the template.

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.

<dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid">
</dike-grid>
@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:

Method
Description

setColumnEditable()

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:

<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>
@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:

  1. Gender default template. When you click on this button, you will set the default template again.

  2. Gender custom template. This action will assign the custom edition template.

  3. Email default template. It will establish the default edition template.

  4. 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.

<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>
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();
    });
  }
}

You will have access to the corresponding FormControl and the options provided in the object.

For further details, see the definition.

Edition templates
EditionFieldSettings
DikeGridColumnDef
Default Edition templates
Default edition templates - Multiple options
Custom Edition templates
Assigning edition templates - Using the API