# Row Edition

## Live example

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

## Allowing edition

To allow the user to edit the DikeGrid rows, you must provide an input property called <mark style="color:orange;">`allowEdition`</mark>.

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

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

{% endcode %}

{% hint style="warning" %}
You can not change the <mark style="color:orange;">`allowEdition`</mark> property at **runtime**.
{% endhint %}

### Edition mode

The <mark style="color:orange;">`allowEdition`</mark> property internally prepares the DikeGrid to support row edition, but you can only set this property at the creation phase.

The edition mode toggles the DikeGrid UI to show the necessary elements to execute edition operations. Therefore, you must provide an input property named <mark style="color:orange;">`editionMode`</mark>.

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

```markup
<dike-grid id="grid-row-edition" height="600px" #grid="dkgGrid"
    allowEdition
    [editionMode]="gridProperties.editionMode">
</dike-grid>
```

{% endcode %}

Open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) for the live example and click on the **Edition mode** checkbox.

![Floating Configuration Panel - Edition](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F02z0J0RWkndtL2X7T3di%2Fgrid-structure-edition-panel-conf.png?alt=media\&token=d32fc072-66ce-4fec-b341-4f4f2827a466)

Once you have enabled the edition mode, you will see an icon (three vertical dots) at the left of every row. When you click on this icon, it will show a contextual menu with the edition operations.

![Enabling the Edition mode](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FlWlqng0CG0u43HrHFEqr%2Frow-edition-enabling-edition-mode.png?alt=media\&token=cd521c02-9c9d-4c9b-87f0-6ce1a2370341)

## Edition actions

Once you have allowed the edition operations and toggled the DikeGrid to the edition mode, you can take a row to the edition state, make some changes to its fields and then cancel the edition or save the changes. Of course, you can also delete the row.

Before exploring the **edition actions**, consider the following column configuration:

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

```markup
<dike-grid id="grid-row-edition" height="600px" #grid="dkgGrid"
    allowEdition
    [editionMode]="gridProperties.editionMode">

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="completeNameGroup"
        headerText="Complete Name">

        <dike-grid-column
            fieldName="firstName"
            headerText="Name"
            dataType="Text"
            width="150"
            sortable
            editable>
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            sortable
            editable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="gender"
        headerText="Gender"
        dataType="Binary"
        width="110"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="age"
        headerText="Age"
        dataType="Numeric"
        contentAlign="center"
        width="100"
        sortable
        editable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        sortable
        editable>
    </dike-grid-column>

</dike-grid>
```

{% endcode %}

We have defined all columns as **editable** except for **EmployeeId**, **Gender**, and **Email** columns.

{% hint style="info" %}
You can not make a column group **editable**.
{% endhint %}

### Row Status

When the DikeGrid wraps the provided entries, it assigns to the row a creation **timestamp**, and a status equals to <mark style="color:red;">`Read`</mark> value.

{% hint style="info" %}
The DikeGrid changes the row status and the timestamp every time an edition operation occurs.
{% endhint %}

The row status values are:

| Edition operation | Row status value                           |
| ----------------- | ------------------------------------------ |
| No operation      | <mark style="color:red;">`Read`</mark>     |
| Edition           | <mark style="color:red;">`Editing`</mark>  |
| Update            | <mark style="color:red;">`Modified`</mark> |
| Remove            | <mark style="color:red;">`Deleted`</mark>  |

### Editing a row

You can **double-click** on a row to change it to the edition state or click on the **Edit** option from the row context menu.

After changing a row to the edition state, the DikeGrid instance shows the default column templates for editing. It also displays an icon (a pencil) indicating editing that row.

![Changing a row to edition state](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FzU1nglVYnjUUxLPF0G90%2Frow-edition-row-edition-state.png?alt=media\&token=a779bf93-cf36-494b-8a42-31504d97db1b)

{% hint style="success" %}
See the Edition Templates section to customize the column templates for editing.
{% endhint %}

### Saving changes

After you have made the changes you needed, you can save those changes by pressing the **ENTER** key or clicking on the **Save** option from the row context menu.

{% hint style="info" %}
Be aware that the DikeGrid will save the edited row if it is **not pristine** and is **valid**. Therefore, the DikeGrid will save the row if you have changed it.
{% endhint %}

Let us add a simple validator to the **Name** column to see validation in action.

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

```markup
<dike-grid-column
    fieldName="completeNameGroup"
    headerText="Complete Name">

    <dike-grid-column
        fieldName="firstName"
        headerText="Name"
        dataType="Text"
        width="150"
        sortable
        editable
        [editionSettings]="{ required: true }">
    </dike-grid-column>
</dike-grid-column>
```

{% endcode %}

We have just made the **Name** column ***required***. If you do not provide a value for the **Name** field, the DikeGrid will show a **red bar** at the left of the **Name** field.

![Column Name - Required validator](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FxhBa7EsfCfHHsrfnhyKK%2Frow-edition-required-validator.png?alt=media\&token=7cb65e51-1162-41c3-a41d-9ad1747d0420)

When you click on the **red bar**, the DikeGrid will show you the **error message** coming from the validator.

{% hint style="success" %}
We have added a basic validator but very common. You can add more validators to a column, even your custom validators. See the [Edition validation](https://docs.dikesoft.com/editing/edition-validation) section for more details.
{% endhint %}

{% hint style="info" %}
After updating the row, the DikeGrid changes the row status to the <mark style="color:red;">`Modified`</mark> value.
{% endhint %}

### Canceling edition

You can cancel the row edition at any time by pressing the **ESC** key or clicking on the **Cancel** option from the row context menu.

{% hint style="info" %}
If you have made changes, you will lose those changes by canceling the row edition.
{% endhint %}

### Deleting a row

You can remove a row by clicking on the **Delete** option from the row context menu.

{% hint style="warning" %}
You can not delete a row if the row is in edition state.
{% endhint %}

{% hint style="info" %}
After deleting a row, the DikeGrid changes the row status to the <mark style="color:red;">`Deleted`</mark> value.
{% endhint %}

## Edition triggers

We named edition triggers those actions that help you interact with the DikeGrid rows in edition state.

There is one edition trigger per edition action except for deletion. Edition triggers work over a single row. We have seen every edition trigger in the previous sections. See the following table:

| Edition action | Edition trigger         |
| -------------- | ----------------------- |
| Edit           | **Double-click**        |
| Save           | Press the **ENTER** key |
| Cancel         | Press the **ESC** key   |

You can disable these edition triggers by providing the related **Injection Tokens** or at the **grid** level.

### Disabling triggers at the grid level

You must provide a <mark style="color:red;">`false`</mark> value to the corresponding flag through the input property named <mark style="color:orange;">`gridEditionSettings`</mark>.

{% hint style="info" %}
The <mark style="color:orange;">`gridEditionSettings`</mark> property is of type <mark style="color:green;">`DikeGridEditionSettings`</mark>. You must provide the corresponding flag related to edition triggers.
{% endhint %}

Let us disable the **ENTER** key corresponding to the **Save** action.

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

```markup
<dike-grid id="grid-row-edition" height="600px" #grid="dkgGrid"
    allowEdition
    [editionMode]="gridProperties.editionMode"
    [gridEditionSettings]="editionSettings">
</dike-grid>
```

{% endtab %}

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

```typescript
@Component({
  selector: 'row-edition',
  templateUrl: './row-edition.component.html',
  styleUrls: ['./row-edition.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RowEditionComponent implements OnInit, OnDestroy {
  // ...
  
  editionSettings: DikeGridEditionSettings<Employee>;

  ngOnInit(): void {
    // Disable the ENTER edition trigger:
    this.editionSettings = { rowEditionEnterkey: false };
  }
}
```

{% endtab %}
{% endtabs %}

Please, open the live example and test if you can **save** a row by pressing the **ENTER** key.

{% hint style="info" %}
You can only set the <mark style="color:orange;">`gridEditionSettings`</mark> property at the **creation** phase.
{% endhint %}

### Disabling triggers by providing an Injection Token

Every edition trigger can be disabled by providing the related Injection Token.

| Edition trigger  | Injection Token                                          |
| ---------------- | -------------------------------------------------------- |
| **Double-click** | <mark style="color:blue;">`ROW_EDITION_DBLCLICK`</mark>  |
| **ENTER** Key    | <mark style="color:blue;">`ROW_EDITION_ENTER_KEY`</mark> |
| **ESC** Key      | <mark style="color:blue;">`ROW_EDITION_ESC_KEY`</mark>   |

Same as before, you must provide a <mark style="color:red;">`false`</mark> value to the corresponding Injection Token.

Let us disable the **ESC** key related to the **Cancel** action.

{% code title="editing.module.ts" %}

```typescript
@NgModule({
  providers: [
    { provide: ROW_EDITION_ESC_KEY, useValue: false }
  ]
})
export class EditingModule { }
```

{% endcode %}

Please, open the live example and test if you can **cancel** the row edition by pressing the **ESC** key.

## Editing using the API

You can perform the edition actions using the corresponding API.

Before using the API, we have to retrieve the DikeGrid instance from the component's view.

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

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

{% endtab %}

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

```typescript
@Component({
  selector: 'row-edition',
  templateUrl: './row-edition.component.html',
  styleUrls: ['./row-edition.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RowEditionComponent implements OnInit, OnDestroy {
  // Retrieve the DikeGridComponent<T> instance from the view:
  @ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;

  //...
}
```

{% endtab %}
{% endtabs %}

### DikeGrid Column API

Using the **column API**, you can make a column **editable** and establish its **edition settings** at **runtime**.

| Method                | Description                                            |
| --------------------- | ------------------------------------------------------ |
| `setColumnEditable()` | Use this method to set or unset a column **editable**. |

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

### DikeGrid Edition API

You can use the **edition API** for managing the edition actions.

The **methods** in the edition API are:

| Method               | Description                                                                                                                                                                                    |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `editRow()`          | This method will change the row status to **edition state**.                                                                                                                                   |
| `updateRow()`        | It **saves** the changes in the given row. The given row must be **valid** a **not pristine**. After updating, the DikeGrid sets the row status to <mark style="color:red;">`Modified`</mark>. |
| `cancelRowEdition()` | It changes the row status to <mark style="color:red;">`Read`</mark> status. This method discards all the changes in the given row.                                                             |
| `removeRow()`        | This method will change the row status to <mark style="color:red;">`Deleted`</mark> status.                                                                                                    |
| `restoreRow()`       | This method will revert any change that the user has made.                                                                                                                                     |

The **properties** in the edition API are:

| Property        | Description                                                |
| --------------- | ---------------------------------------------------------- |
| `rowsInEdition` | It returns the current rows in edition state.              |
| `modifiedRows`  | It returns all the rows that have changes in their fields. |
| `removedRows`   | It returns all the deleted rows.                           |

{% hint style="success" %}
For further details, see the [<mark style="color:green;">`DikeGridEdition`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridedition) definition.
{% endhint %}

{% hint style="info" %}
You do not have to provide the <mark style="color:orange;">`editionMode`</mark> property for **edition API** use. It is enough to allow edition by providing the property named <mark style="color:orange;">`allowEdition`</mark>.
{% endhint %}

To see the API in action, let us define the following API:

{% tabs %}
{% tab title="row-edition.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)="onEditRow()"
            [disabled]="!isFiltered">editRow - filtered
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onEmailEditable()">Email - editable
        </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)="onUpdateRow()">updateRow
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onRestoreRowModified()">restoreRow - modified
        </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)="onCancelRowEdition()">cancelRowEdition
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onRemoveRow()">removeRow - filtered
        </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)="onRestoreRowDeleted()">restoreRow - deleted
        </button>
    </div>
</div>
```

{% endtab %}

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

```typescript
onEditRow(): void {
  // Take all rows that are not being edited from filtered rows:
  const filteredRows = this.dikeGrid.filter.getFilteredRows().filter(row => !row.isEditing);

  // You can only have one row in edition state:
  if (filteredRows.length > 0 && this.dikeGrid.edition.rowsInEdition.length === 0) {
    // Take the first row and change it to the edition mode:
    this.dikeGrid.edition.editRow(filteredRows[0]);
  }
}

onEmailEditable(): void {
  // Get the Email column:
  const emailColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'email');

  // The column exist and is a data column:
  if (!!emailColumn && isDikeDataColumnDef(emailColumn)) {
    // Toggle the editable value:
    this.dikeGrid.columnDef.setColumnEditable(emailColumn, !emailColumn.editable, { editionSettings: { required: true } });
  }
}

onUpdateRow(): void {
  // Take the row in edition and update it:
  if (this.dikeGrid.edition.rowsInEdition.length === 1) {
    // The DikeGrid intance will not update the given row if the row is pristine and not valid:
    this.dikeGrid.edition.updateRow(this.dikeGrid.edition.rowsInEdition[0]);
  }
}

onRestoreRowModified(): void {
  // Take the row from the modified rows set:
  if (this.dikeGrid.edition.modifiedRows.length === 1) {
    // Restore the row to its immediate previous state:
    this.dikeGrid.edition.restoreRow(this.dikeGrid.edition.modifiedRows[0]);
  }
}

onCancelRowEdition(): void {
  // Take the row that it is being edited:
  if (this.dikeGrid.edition.rowsInEdition.length === 1) {
    this.dikeGrid.edition.cancelRowEdition(this.dikeGrid.edition.rowsInEdition[0]);
  }
}

onRemoveRow(): void {
  // Take all rows that are not being edited from filtered rows:
  const filteredRows = this.dikeGrid.filter.getFilteredRows().filter(row => !row.isEditing);

  // You can only have one row in edition state:
  if (filteredRows.length > 0) {
    // Remove the first row from the final set:
    this.dikeGrid.edition.removeRow(filteredRows[0]);
  }
}

onRestoreRowDeleted(): void {
  // Take the row from the deleted rows set:
  if (this.dikeGrid.edition.removedRows.length > 0) {
    // Restore the row to its immediate previous state:
    this.dikeGrid.edition.restoreRow(this.dikeGrid.edition.removedRows[0]);
  }
}

onRowsInEdition(): void {
  console.log('Rows in edition: ', this.dikeGrid.edition.rowsInEdition);
}

onModifiedRows(): void {
  console.log('Modified rows: ', this.dikeGrid.edition.modifiedRows);
}

onRemovedRows(): void {
  console.log('Removed rows: ', this.dikeGrid.edition.removedRows);
}
```

{% endtab %}
{% endtabs %}

The previous definition generates the following output:

![Row Edition - Using the API](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FVuiwWeMxaaDIm2DXqYhD%2Frow-edition-using-api.png?alt=media\&token=b26fe40d-6d40-44b0-a8c7-7f38712087f5)

You can only have one row in edition state, and we have enabled the In-line filters.

We describe every button in the following list.

1. **Email - editable**. Click on this button to make the **Email** column editable or not editable. It toggles the current editable value, and it is marked as **required**.
2. **editRow - filtered**. It changes one row from filtered set to edition state. It will be disabled if there are no filtered rows.
3. **updateRow**. It saves the changes of the row in edition mode.
4. **restoreRow - modified**. It reverts changes from a modified row. You can revert all the changes you have made.
5. **cancelRowEdition**. It cancels the edition of the row in edition state.
6. **removeRow** **- filtered**. It takes a row from the filtered set and removes it.
7. **restoreRow - deleted**. It restores a row from the deleted rows set.
8. **Rows in edition**. It prints the row in edition mode.
9. **Modified rows**. It prints all the rows that have been modified.
10. **Removed rows**. It prints all the rows that have been deleted.

## Edition events

When performing the edition actions, the DikeGrid instance **emits** the corresponding events.

Events regarding edition actions are:

| Event                    | Description                                             |
| ------------------------ | ------------------------------------------------------- |
| `editionRowChange`       | It emits the row that has been changed to edition mode. |
| `updateRowChange`        | It emits the modified rows.                             |
| `cancelRowEditionChange` | It emits the rows that have been canceled for edition.  |
| `removeRowChange`        | It emits the rows that have been deleted.               |
| `restoreRowChange`       | It emits the rows whose changes were reverted.          |

Let us listen to these events:

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

```markup
<dike-grid id="grid-row-edition" height="600px" #grid="dkgGrid"
    (editionRowChange)="onEditionRowChange($event)"
    (updateRowChange)="onUpdateRowChange($event)"
    (cancelRowEditionChange)="onCancelRowEditionChange($event)"
    (removeRowChange)="onRemoveRowChange($event)"
    (restoreRowChange)="onRestoreRowChange($event)">
</dike-grid>
```

{% endtab %}

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

```typescript
onEditionRowChange(value: DikeGridDataRowEntry<Employee>): void {
  console.log('editionRowChange: ', value);
}

onUpdateRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
  console.log('updateRowChange: ', value);
}

onCancelRowEditionChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
  console.log('cancelRowEditionChange: ', value);
}

onRemoveRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
  console.log('removeRowChangeChange: ', value);
}

onRestoreRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
  console.log('restoreRowChange: ', value);
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
Please, open your **dev console** to see the output of these events.
{% endhint %}

{% hint style="success" %}
You can also listen to these events from the [<mark style="color:green;">`DikeGridEdition`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridedition#events) instance.
{% endhint %}

## Summary

You allow the edition by providing a property named <mark style="color:orange;">`allowEdition`</mark>. Then, to let the user **toggle** to the **edition mode**, provide a property called <mark style="color:orange;">`editioMode`</mark>. Finally, you define a column as **editable** to modify the column value.&#x20;

In this section, we have explored how to edit one row at a time using the UI or the API.

### Complete code for this section

{% tabs %}
{% tab title="row-edition.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)="onEditRow()"
            [disabled]="!isFiltered">editRow - filtered
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onEmailEditable()">Email - editable
        </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)="onUpdateRow()">updateRow
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onRestoreRowModified()">restoreRow - modified
        </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)="onCancelRowEdition()">cancelRowEdition
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onRemoveRow()">removeRow - filtered
        </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)="onRestoreRowDeleted()">restoreRow - deleted
        </button>
    </div>
</div>

<mat-divider class="m-6"></mat-divider>

<div class="mt-2 flex flex-row flex-wrap items-center justify-around">
    <button mat-raised-button
        class="flex-none w-56 my-2"
        color="primary"
        (click)="onRowsInEdition()">Rows in edition
    </button>

    <button mat-raised-button
        class="flex-none w-56 my-2"
        color="primary"
        (click)="onModifiedRows()">Modified rows
    </button>

    <button mat-raised-button
        class="flex-none w-56 my-2"
        color="primary"
        (click)="onRemovedRows()">Removed rows
    </button>
</div>

<dike-grid id="grid-row-edition" height="600px" #grid="dkgGrid"
    [displayRowId]="gridProperties.displayRowId"
    [gridElevation]="gridProperties.matElevation"
    [gridElevationValue]="gridProperties.elevationValue"
    [striped]="gridProperties.stripeRows"
    [verticalRowLines]="gridProperties.verticalRowLines"

    allowEdition
    [editionMode]="gridProperties.editionMode"
    [allowSorting]="gridProperties.allowSorting"
    [allowRowFiltering]="gridProperties.allowRowFilter"

    [gridEditionSettings]="editionSettings"

    (editionRowChange)="onEditionRowChange($event)"
    (updateRowChange)="onUpdateRowChange($event)"
    (cancelRowEditionChange)="onCancelRowEditionChange($event)"
    (removeRowChange)="onRemoveRowChange($event)"
    (restoreRowChange)="onRestoreRowChange($event)"
    (filterChange)="onFilterChange($event)"

    [datasource]="dkgDataSource">

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="completeNameGroup"
        headerText="Complete Name">

        <dike-grid-column
            fieldName="firstName"
            headerText="Name"
            dataType="Text"
            width="150"
            sortable
            editable
            [editionSettings]="{ required: true }">
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            sortable
            editable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="gender"
        headerText="Gender"
        dataType="Binary"
        width="110"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="age"
        headerText="Age"
        dataType="Numeric"
        contentAlign="center"
        width="100"
        sortable
        editable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300"
        sortable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        sortable
        editable>
    </dike-grid-column>

</dike-grid>
```

{% endtab %}

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

```typescript
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs';

import { DikeFilterable, DikeGridComponent, DikeGridDataRowEntry,
    DikeGridDataSourceInput, DikeGridEditionSettings, 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: 'row-edition',
  templateUrl: './row-edition.component.html',
  styleUrls: ['./row-edition.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RowEditionComponent implements OnInit, OnDestroy {
  // Retrieve the DikeGridComponent<T> instance from the view:
  @ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  editionSettings: DikeGridEditionSettings<Employee>;
  isFiltered: boolean;

  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

  constructor(
    private cdr: ChangeDetectorRef,
    private gridConfig: DikeGridConfig,
    private sampleData: SampleData) {

    this.isFiltered = false;
  }

  ngOnInit(): void {
    // Get 1000 entries from the REST API:
    this.dkgDataSource = this.sampleData.getEmployees(1000);
    // Listening to any config property change:
    this.setChangeGridPropertiesSubscription();
    // Disable the ENTER edition trigger:
    this.editionSettings = { rowEditionEnterkey: false };
  }

  ngOnDestroy(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
  }

  onEditRow(): void {
    // Take all rows that are not being edited from filtered rows:
    const filteredRows = this.dikeGrid.filter.getFilteredRows().filter(row => !row.isEditing);

    // You can only have one row in edition state:
    if (filteredRows.length > 0 && this.dikeGrid.edition.rowsInEdition.length === 0) {
      // Take the first row and change it to the edition mode:
      this.dikeGrid.edition.editRow(filteredRows[0]);
    }
  }

  onEmailEditable(): void {
    // Get the Email column:
    const emailColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'email');

    // The column exist and is a data column:
    if (!!emailColumn && isDikeDataColumnDef(emailColumn)) {
      // Toggle the editable value:
      this.dikeGrid.columnDef.setColumnEditable(emailColumn, !emailColumn.editable, { editionSettings: { required: true } });
    }
  }

  onUpdateRow(): void {
    // Take the row in edition and update it:
    if (this.dikeGrid.edition.rowsInEdition.length === 1) {
      // The DikeGrid intance will not update the given row if the row is pristine and not valid:
      this.dikeGrid.edition.updateRow(this.dikeGrid.edition.rowsInEdition[0]);
    }
  }

  onRestoreRowModified(): void {
    // Take the row from the modified rows set:
    if (this.dikeGrid.edition.modifiedRows.length === 1) {
      // Restore the row to its immediate previous state:
      this.dikeGrid.edition.restoreRow(this.dikeGrid.edition.modifiedRows[0]);
    }
  }

  onCancelRowEdition(): void {
    // Take the row that it is being edited:
    if (this.dikeGrid.edition.rowsInEdition.length === 1) {
      this.dikeGrid.edition.cancelRowEdition(this.dikeGrid.edition.rowsInEdition[0]);
    }
  }

  onRemoveRow(): void {
    // Take all rows that are not being edited from filtered rows:
    const filteredRows = this.dikeGrid.filter.getFilteredRows().filter(row => !row.isEditing);

    // You can only have one row in edition state:
    if (filteredRows.length > 0) {
      // Remove the first row from the final set:
      this.dikeGrid.edition.removeRow(filteredRows[0]);
    }
  }

  onRestoreRowDeleted(): void {
    // Take the row from the deleted rows set:
    if (this.dikeGrid.edition.removedRows.length > 0) {
      // Restore the row to its immediate previous state:
      this.dikeGrid.edition.restoreRow(this.dikeGrid.edition.removedRows[0]);
    }
  }

  onRowsInEdition(): void {
    console.log('Rows in edition: ', this.dikeGrid.edition.rowsInEdition);
  }

  onModifiedRows(): void {
    console.log('Modified rows: ', this.dikeGrid.edition.modifiedRows);
  }

  onRemovedRows(): void {
    console.log('Removed rows: ', this.dikeGrid.edition.removedRows);
  }

  onEditionRowChange(value: DikeGridDataRowEntry<Employee>): void {
    console.log('editionRowChange: ', value);
  }

  onUpdateRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
    console.log('updateRowChange: ', value);
  }

  onCancelRowEditionChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
    console.log('cancelRowEditionChange: ', value);
  }

  onRemoveRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
    console.log('removeRowChangeChange: ', value);
  }

  onRestoreRowChange(value: DikeGridDataRowEntry<Employee> | DikeGridDataRowEntry<Employee>[]): void {
    console.log('restoreRowChange: ', value);
  }

  onFilterChange(filterable: DikeFilterable<Employee>): void {
    // We ignore the argument filterable because we are only interested in the action.
    this.isFiltered = !!this.dikeGrid ? this.dikeGrid.filter.isFilterApplied() : false;
  }

  private setChangeGridPropertiesSubscription(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
    this.changeGridPropertiesSubscription = this.gridConfig.configChange.subscribe((props: DikeGridProperties) => {
      this.gridProperties = props;
      this.cdr.markForCheck();
    });
  }
}
```

{% endtab %}

{% tab title="editing.module.ts" %}

```typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';

import { CustomErrorMessage, CUSTOM_EDITION_ERROR_MESSAGES, DikeDataGridModule,
    ErrorType, MAX_ROWS_IN_EDITION, ROW_EDITION_ESC_KEY,
    WAIT_FOR_MULTIPLE_ROWS_CANCELATION
} from '@dikesoft/angular-data-grid';

import { SharedModule } from 'app/shared/shared.module';
import { editingRoutes } from 'app/modules/admin/editing/editing.routing';

import { RowEditionComponent } from './row-edition/row-edition.component';
import { EditionTemplatesComponent } from './edition-templates/edition-templates.component';
import { EditionValidationComponent } from './edition-validation/edition-validation.component';
import { MultipleRowsEditionComponent } from './multiple-rows-edition/multiple-rows-edition.component';

@NgModule({
  declarations: [
    RowEditionComponent,
    EditionTemplatesComponent,
    EditionValidationComponent,
    MultipleRowsEditionComponent
  ],
  imports: [
    CommonModule,
    RouterModule.forChild(editingRoutes),

    SharedModule,
    DikeDataGridModule
  ],
  providers: [
    { provide: ROW_EDITION_ESC_KEY, useValue: false },
    { provide: CUSTOM_EDITION_ERROR_MESSAGES,
      useFactory: (): CustomErrorMessage =>
        new CustomErrorMessage()
            .addMessage(ErrorType.REQUIRED, 'You can not leave the field empty.')
    },
    { provide: MAX_ROWS_IN_EDITION, useValue: 5 },
    { provide: WAIT_FOR_MULTIPLE_ROWS_CANCELATION, useValue: false }
  ]
})
export class EditingModule { }

```

{% endtab %}
{% endtabs %}
