# Edition templates

## Live example

{% hint style="success" %}
[Edition templates](https://demos.dikesoft.com/dk-grid/editing/edition-templates) live example.
{% endhint %}

## 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 <mark style="color:red;">`text`</mark>.   |
| `Numeric`   | A Material Form field with an input element with type equals <mark style="color:red;">`number`</mark>. |
| `Date`      | A Material Form field with a Material Datepicker inside.                                               |
| `Binary`    | A Material checkbox.                                                                                   |

Let us make some columns editable:

{% code title="edition-templates.component.html" %}

```markup
<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>
```

{% endcode %}

The previous initial configuration generates the following output:

![Default Edition templates](/files/raHQ7hQ9NeObKOIJurTl)

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 <mark style="color:red;">`female`</mark> and <mark style="color:red;">`male`</mark>. 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`      | <mark style="color:green;">`DikeTextSelectionModel`</mark>    |
| `Numeric`   | <mark style="color:green;">`DikeNumericSelectionModel`</mark> |
| `Binary`    | <mark style="color:green;">`DikeBinarySelectionModel`</mark>  |

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

{% tabs %}
{% tab title="edition-templates.component.html" %}

```markup
<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>
```

{% endtab %}

{% tab title="edition-templates.component.ts" %}

```typescript
@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 }
      ];
  }
}
```

{% endtab %}
{% endtabs %}

![Default edition templates - Multiple options](/files/IYsKds11HdX6ci523O0t)

{% hint style="warning" %}
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.
{% endhint %}

{% hint style="info" %}
For `Text` and `Numeric` columns, you can provide any number of options.
{% endhint %}

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

{% tabs %}
{% tab title="edition-templates.component.html" %}

```markup
<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>
```

{% endtab %}

{% tab title="edition-templates.component.ts" %}

```typescript
@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);
  }
}
```

{% endtab %}
{% endtabs %}

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.

![Custom Edition templates](/files/cGHdHz4PrXah5aIoqJHI)

{% hint style="success" %}
You will have access to the corresponding <mark style="color:green;">`FormControl`</mark> and the options provided in the [<mark style="color:green;">`EditionFieldSettings`</mark>](/reference/interfaces/editing.md#editionfieldsettings) object.
{% endhint %}

{% hint style="info" %}
The <mark style="color:orange;">`editionTemplate`</mark> and <mark style="color:orange;">`displayTemplate`</mark> properties accept a <mark style="color:green;">`TemplateRef`</mark> or an <mark style="color:green;">`Observable`</mark> of a <mark style="color:green;">`TemplateRef`</mark>.
{% endhint %}

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

{% tabs %}
{% tab title="edition-templates.component.html" %}

```markup
<dike-grid id="grid-edition-templates" height="600px" #grid="dkgGrid">
</dike-grid>
```

{% endtab %}

{% tab title="edition-templates.component.ts" %}

```typescript
@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>;
  
  //...
  
}
```

{% endtab %}
{% endtabs %}

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

{% hint style="success" %}
For further details, see the [<mark style="color:green;">`DikeGridColumnDef`</mark>](/reference/dkgrid-api/dkgridcolumndef.md#methods) definition.
{% endhint %}

To see the API in action, consider the following configuration:

{% tabs %}
{% tab title="edition-templates.component.html" %}

```markup
<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>
```

{% endtab %}

{% tab title="edition-templates.component.ts" %}

```typescript
@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);
    }
  }
}
```

{% endtab %}
{% endtabs %}

The previous definition generates the following output:

![Assigning edition templates - Using the API](/files/w0yjSk75BHLaEfCs8Zqt)

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.

{% hint style="info" %}
As you can see, when changing the template, the DikeGrid re-renders the view for that column.
{% endhint %}

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

{% tabs %}
{% tab title="edition-templates.component.html" %}

```markup
<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>

```

{% endtab %}

{% tab title="edition-templates.component.ts" %}

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

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dikesoft.com/editing/edition-templates.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
