# Multiple rows edition

## Live example

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

## Edition actions

Before exploring the edition actions, do not forget to **allow edition** and enable the **edition mode**.

{% hint style="info" %}
Remember that the edition mode will display all the UI elements for editing rows.
{% endhint %}

We start defining some **editable** columns.

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

```markup
<dike-grid id="grid-multiple-rows-edition" 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
            [editionSettings]="{ required: true }">
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            editable
            [editionSettings]="{ required: true }">
        </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]="{ required: true }">
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300"
        editable
        [editionSettings]="emailEditionSettings"
        [editionTemplate]="emailEdition">
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        editable
        [editionSettings]="{ required: true }">
    </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>
```

{% endcode %}

We have configured the following features:

1. All the columns are **editable** except for the **Employee Id** column.
2. All editable columns are **required**, and we have set **templates** for the **Gender** and **Email** columns.
3. You can toggle to the **edition mode** from the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel).

When the DikeGrid is in the edition mode, it shows 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 per row.

At the same time, the DikeGrid shows an **icon** (**three horizontal dots**) in the header at the left of the first visible column header. When you click on this icon, it will show a contextual menu with the edition operations for multiple rows.

![Multiple rows edition - Contextual menu](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FMQo6gyCqoHMCNkuR5EuS%2Fmultiple-rows-edition-contextual-menu.png?alt=media\&token=1ad146d6-adc0-4c0f-ad9a-54b173f009df)

### Editing rows

Let us start editing some rows by **double-clicking** on them. This action will display the edition templates for each **editable** column.

The DikeGrid allows you to have up to **10 rows** in edition state by default, but you can change this value by providing the corresponding value.

You can change the maximum rows in the edition state value by providing an **Injection Token** or at the **grid** level.

| Variable                                                                                   | Description                                                                                             |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| <mark style="color:blue;">`MAX_ROWS_IN_EDITION`</mark>                                     | This value affects all your DikeGrid instances that live under the place you give your Injection Token. |
| <mark style="color:green;">`DikeGridEditionSettings { maxRowsInEdition?: number };`</mark> | Providing at this level only affects the DikeGrid instance that receives the value.                     |

Let us provide the <mark style="color:blue;">`MAX_ROWS_IN_EDITION`</mark> token:

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

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

{% endcode %}

When you reach the maximum number of rows in the edition state, the DikeGrid will show you a message indicating it.

![Maximum rows in the edition state message](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FTj2jeSgHvvT3ahQTgqQ6%2Fmultiple-rows-edition-reach-max-rows.png?alt=media\&token=6bcf9653-9363-48e1-8924-6300fb6ab26c)

### Saving rows

Once you have made some changes to some rows, you can save these rows by clicking on the **Save** option from the contextual menu in the header.

{% hint style="warning" %}
Be aware that the DikeGrid will enable the **Save** option if all rows in the edition state are **valid** and at least one is **not pristine**. Therefore, the DikeGrid will save those valid rows which are not pristine.
{% endhint %}

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

{% hint style="success" %}
Please, open the live example to test the **Save** operation.
{% endhint %}

### Canceling edition

When you have some rows in the edition state, the first enabled option in the contextual menu is **Cancel**.

Clicking on the Cancel option in the context menu will cancel the edition of all the rows in the edition state.

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

### Deleting rows

To delete rows from the DikeGrid UI, you must enable the **selection** operation. Therefore, you can delete only the selected rows from the UI.

The **Remove** option appears in the contextual menu if you allow the user to select rows, and the DikeGrid will enable it only when the user has selected one row at least.

Let us provide the corresponding input property to enable the selection operation.

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

```markup
<dike-grid id="grid-multiple-rows-edition" height="600px" #grid="dkgGrid"
    [allowSelection]="gridProperties.allowSelection">
</dike-grid>
```

{% endcode %}

You can open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) and click on the **Allow Selection** checkbox.

![Floating Configuration Panel - Selection](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FR0ZZq1Pf1grFV8IN86tZ%2Fselection-panel-conf.png?alt=media\&token=1756c6f8-11e7-499d-a420-228c9c2e57cb)

Now the context menu shows the **Remove** option.

![Multiple rows edition - Remove option](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FHO3zxtEQ66DeFqsrhxQj%2Fmultiple-rows-edition-delete-option.png?alt=media\&token=0322e171-27bc-472a-a042-1b50848b50da)

{% hint style="info" %}
If the user has selected rows in the edition state, the DikeGrid will not delete them.
{% endhint %}

## Reverting changes

You can undo changes from the modified or deleted rows. Therefore, you have to change the view from the UI to display only **modified** or **deleted** rows.

### Edition filters

If you open the context menu, you can see an option called **Edition Filter**, and under this option, you will find the edition subsets options.

![Multiple rows edition - Edition filters](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F6ysQJormdIHERXI8Fehs%2Fmultiple-rows-edition-edition-filters.png?alt=media\&token=0b87ccd4-0aac-44f0-88b6-02d1d30caf0d)

{% hint style="info" %}
The DikeGrid will take the user to the **edition view** by clicking on these edition subsets options.
{% endhint %}

### Option - Editing

Clicking on this menu option will display only the rows in the edition state. Showing only the rows editing is helpful when you have grouped the rows, for instance, because the rows in the edition state could be in different groups.

![Edition Filter - Editing option](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FcJLwl2Fv9dsZcn2Hu8Tb%2Fmultiple-rows-edition-edition-filters-editing.png?alt=media\&token=8e89b4f3-8964-4f34-90d2-02f30cf20030)

As you can see, the icon in the header changes to a **pencil icon** (instead of the three horizontal dots), indicating that you are viewing only the rows in the edition state.

### Option - Modified

This menu option shows only those rows that have suffered changes. When you navigate to the **modified-rows** view, you will see an icon with a **badge** at the left of every row. The badge indicates how many times the user has changed the row.

![Edition Filter - Modified option](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F4WgLo8mLmK7OvAYVB9lp%2Fmultiple-rows-edition-edition-filters-modified.png?alt=media\&token=7377fc63-a813-422c-9df0-7c7be1dbe17a)

You click on the icon with a badge to **revert** the changes in the row. This action will take the row to its **immediate previous state**.

{% hint style="success" %}
You can click on the icon with a badge until the row reaches its initial state. The initial state corresponds to the row state equals to <mark style="color:red;">`Read`</mark> value.
{% endhint %}

If you have enabled the **selection** operation, you can select more than one row and take them to their immediate previous state by clicking on the **Restore** option from the contextual menu.

![Restoring changes for multiple rows](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Fh1wrusQ6zEJgO9s9OoZ7%2Fmultiple-rows-edition-restore-selected.png?alt=media\&token=1de518ee-6241-424b-95b0-4bb8c7e9b47e)

Once again, see how the DikeGrid changes the icon to indicate that you are viewing the **modified** rows.

### Option - Removed

This menu option shows only the subset of rows that corresponds to the deleted rows. When you are in the **deleted-rows** view, you will see an icon with a **badge** at the left of every row. Again, the badge indicates how many times the user has changed the row, but this time the last action corresponds to the deletion operation.

![Edition Filter - Removed option](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FgiMyOcy36u2u72znZuVT%2Fmultiple-rows-edition-edition-filters-removed.png?alt=media\&token=a34992ab-58ee-43f2-8d26-6615b27d03b8)

{% hint style="info" %}
If the badge displays a number greater than one means that the row has suffered changes before deleting it.
{% endhint %}

The DikeGrid changes the icon in the header to indicate that you are viewing the **deleted** rows.

If you have enabled the selection operation, you can select more than one row and **restore** them by clicking on the **Restore** option from the contextual menu.

![Restoring multiple removed rows](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FM4gKM225SFIZQzuOFTcj%2Fmultiple-rows-edition-restore-removed-selected.png?alt=media\&token=3017fc02-17e9-4d91-b9b6-9493732e57a6)

### Option - Back

You can display the **standard view** by clicking on the **Back** option.

{% hint style="success" %}
You can filter every edition subset of rows by typing values in a **filterable** column. The values you enter in the **Edition Filters** view are independent of the values in the standard view.
{% endhint %}

## Edition Toolbar

All the edition actions for multiple rows are available through the Edition Toolbar. When you display the Edition Toolbar, the DikeGrid hides the contextual menu in the header.

If you want to use the Edition Toolbar in the live example, open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) and click on the **Edition Toolbar** 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)

When displaying the Edition Toolbar, the DikeGrid still shows the icon in the header but does not show the contextual menu.

![Multiple rows edition - Toolbar](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FTysuh3oKCMdBSYmjoUuH%2Fmultiple-rows-edition-toolbar.png?alt=media\&token=a1d5f7ee-4bd9-4b99-9afa-cdf35d3e26d2)

### Customizing the Edition Toolbar

You can change the appearance of the Edition Toolbar by modifying its **height**, **alignment**, or **position**. You can also change the **size** of its items.

{% hint style="success" %}
For further details, see the [Grid Structure - Edition Toolbar](https://docs.dikesoft.com/fundamentals/grid-structure/edition-toolbar) section.
{% endhint %}

## DikeGrid Edition API

You can perform the edition actions using the **edition API**.

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

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

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

{% endtab %}

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

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

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

{% endtab %}
{% endtabs %}

The following method operates over multiple rows edition.

| Method                  | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `updateRowsInEdition()` | This method takes all valid rows which are not pristine and saves their changes.                                                                                                                                                                                                                                                                                                                                                                                     |
| `removeRows()`          | It removes from the given rows only those rows that are not in the edition state and do not have the <mark style="color:red;">`Deleted`</mark> value in their row status.                                                                                                                                                                                                                                                                                            |
| `cancelRowsInEdition()` | It cancels the current edition state for every row, losing all the changes you have made.                                                                                                                                                                                                                                                                                                                                                                            |
| `restoreRows()`         | It takes the given rows to their immediate previous row state. It filters the given rows taking only those **modified** or **deleted** rows.                                                                                                                                                                                                                                                                                                                         |
| `setEditionFilter()`    | <p>It displays the corresponding subset of rows editing. Invoking this method is equivalent to clicking on the contextual menu's <strong>Editing</strong>, <strong>Modified</strong>, or <strong>Removed</strong> options.</p><p>Since this method changes the view of the DikeGrid, you should have provided the <mark style="color:orange;"><code>allowEdition</code></mark> and <mark style="color:orange;"><code>editionMode</code></mark> input properties.</p> |
| `cancelEditionFilter()` | Invoking this method, the DikeGrid will show the **standard view**. It is equivalent to clicking on the **Back** option of the contextual menu.                                                                                                                                                                                                                                                                                                                      |

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

{% hint style="info" %}
It is enough to set the input property called <mark style="color:orange;">`allowEdition`</mark> to use the edition API.
{% endhint %}

To see the API in action, consider the following additions to the UI:

{% tabs %}
{% tab title="multiple-rows-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)="onSaveRows()">Save rows
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onCancelEdition()">Cancel Edition
        </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)="onRemoveRows()">Remove rows
        </button>
    </div>

    <div class="flex-none w-60 flex flex-col m-2 items-center">
        <mat-radio-group class="flex-none w-56 flex flex-row justify-between" [formControl]="rowTypecontrol">
            <mat-radio-button value="modified">Modified</mat-radio-button>
            <mat-radio-button value="removed">Removed</mat-radio-button>
          </mat-radio-group>

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

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

{% endtab %}

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

```typescript
onSaveRows(): void {
  this.dikeGrid.edition.updateRowsInEdition();
}

onCancelEdition(): void {
  this.dikeGrid.edition.cancelRowsInEdition();
}

onRemoveRows(): void {
  // Delete the selected rows:
  this.dikeGrid.edition.removeRows(this.dikeGrid.selection.getSelectedRows());
}

onRestoreRows(): void {
  if (this.rowTypecontrol.valid) {
    const rows = this.rowTypecontrol.value as string === 'modified' ? this.dikeGrid.edition.modifiedRows :
      this.dikeGrid.edition.removedRows;

    this.dikeGrid.edition.restoreRows(rows);
  }
}
```

{% endtab %}
{% endtabs %}

The previous definition generates the following output:

![Multiple rows edition using the API](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F7BWRSSSpEg5jv8jOT9mK%2Fmultiple-rows-edition-using-api.png?alt=media\&token=071cbde3-f147-4dcf-a4eb-89c2338f082e)

We have added the following buttons:

1. **Save rows**. This action updates the rows in edition state. Remember that the DikeGrid will save only those valid rows that are not pristine.
2. **Cancel Edition**. Clicking on this button will cancel the edition state for every row editing.
3. **Remove rows**. Click on this button to delete the selected rows. The DikeGrid will not remove the rows in the edition state.
4. **Restore rows**. This action works over the **modified** or **deleted** rows. Therefore, you select which type of rows the DikeGrid will restore.

## Edition events

The edition events for multiple rows are the same when working over one row. Regarding the various rows edition, the DikeGrid emits an array of rows instead of one row.

We listen to these events:

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

```markup
<dike-grid id="grid-multiple-rows-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="multiple-rows-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" %}
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 %}

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

## Blocking the UI

When you click on any edition option from the contextual menu, the DikeGrid shows the **Processing Indicator** to block its UI until the updating ends.

{% hint style="info" %}
For further details on blocking the DikeGrid UI, see the [Grid Structure - Waiting Indicator](https://docs.dikesoft.com/fundamentals/grid-structure/waiting-indicator) section.
{% endhint %}

You can avoid the DikeGrid displaying the Processing Indicator by providing a <mark style="color:red;">`false`</mark> value through the related **Injection Token** or at the **grid** level.

You can provide any of the following Injection Tokens depending on the edition action:

| Edition action | Injection Token                                                       |
| -------------- | --------------------------------------------------------------------- |
| Save           | <mark style="color:blue;">`WAIT_FOR_MULTIPLE_ROWS_UPDATE`</mark>      |
| Cancel         | <mark style="color:blue;">`WAIT_FOR_MULTIPLE_ROWS_CANCELATION`</mark> |
| Remove         | <mark style="color:blue;">`WAIT_FOR_MULTIPLE_ROWS_DELETION`</mark>    |
| Restore        | <mark style="color:blue;">`WAIT_FOR_MULTIPLE_ROWS_RESTORATION`</mark> |

If you want to apply the value for a particular DikeGrid instance, provide the corresponding variable through the <mark style="color:green;">`DikeGridEditionsSettings`</mark> reference:

| Edition action | Variable                         |
| -------------- | -------------------------------- |
| Save           | `waitForMultipleRowsUpdate`      |
| Cancel         | `waitForMultipleRowsCancelation` |
| Remove         | `waitForMultipleRowsDeletion`    |
| Restore        | `waitForMultipleRowsRestoration` |

Let us provide the <mark style="color:blue;">`WAIT_FOR_MULTIPLE_ROWS_CANCELATION`</mark> Injection Token to avoid displaying the Processing Indicator when canceling the edition.

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

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

{% endcode %}

## Summary

Apart from saving changes for one row, you can **update multiples rows** simultaneously. However, be aware that you must **enable** the **selection** operation for **deleting** and **restoring** multiple rows.

You must navigate to the edition view for **restoring** rows by clicking on the corresponding **edition filter**. Every row shows an icon with a **badge** conveying how many times the row has suffered changes.

You can perform the edition actions for multiple rows using the **edition API**. Moreover, the DikeGrid **emits** the related **event** for every edition action.

### Complete code for this section

{% tabs %}
{% tab title="multiple-rows-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)="onSaveRows()">Save rows
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onCancelEdition()">Cancel Edition
        </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)="onRemoveRows()">Remove rows
        </button>
    </div>

    <div class="flex-none w-60 flex flex-col m-2 items-center">
        <mat-radio-group class="flex-none w-56 flex flex-row justify-between" [formControl]="rowTypecontrol">
            <mat-radio-button value="modified">Modified</mat-radio-button>
            <mat-radio-button value="removed">Removed</mat-radio-button>
          </mat-radio-group>

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

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

    allowEdition
    [editionMode]="gridProperties.editionMode"
    [allowSelection]="gridProperties.allowSelection"
    [editionToolbar]="gridProperties.displayEditionToolbar"
    [editionToolbarRowHeight]="gridProperties.editionToolbarHeight"
    [editionToolbarItemHeight]="gridProperties.edtitionToolbarItemHeight"
    [editionToolbarPosition]="gridProperties.editionToolbarPosition"
    [editionToolbarAlignment]="gridProperties.editionToolbarAlignment"

    (editionRowChange)="onEditionRowChange($event)"
    (updateRowChange)="onUpdateRowChange($event)"
    (cancelRowEditionChange)="onCancelRowEditionChange($event)"
    (removeRowChange)="onRemoveRowChange($event)"
    (restoreRowChange)="onRestoreRowChange($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
            [editionSettings]="{ required: true }">
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            editable
            [editionSettings]="{ required: true }">
        </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]="{ required: true }">
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300"
        editable
        [editionSettings]="emailEditionSettings"
        [editionTemplate]="emailEdition">
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        editable
        [editionSettings]="{ required: true }">
    </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>

```

{% endtab %}

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

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

import { DikeGridComponent, DikeGridDataRowEntry, DikeGridDataSourceInput, EditionFieldSettings } 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: 'multiple-rows-edition',
  templateUrl: './multiple-rows-edition.component.html',
  styleUrls: ['./multiple-rows-edition.component.scss'],

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

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  emailEditionSettings: EditionFieldSettings;
  rowTypecontrol: FormControl;

  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

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

  ngOnInit(): void {
    // Get 1000 entries from the REST API:
    this.dkgDataSource = this.sampleData.getEmployees(1000);
    // Listening to any config property change:
    this.setChangeGridPropertiesSubscription();
    // Set validators for the Email column:
    this.emailEditionSettings = { required: true, validators: [ Validators.email ] };

    this.rowTypecontrol = new FormControl('modified', Validators.required);
  }

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

  onSaveRows(): void {
    this.dikeGrid.edition.updateRowsInEdition();
  }

  onCancelEdition(): void {
    this.dikeGrid.edition.cancelRowsInEdition();
  }

  onRemoveRows(): void {
    // Delete the selected rows:
    this.dikeGrid.edition.removeRows(this.dikeGrid.selection.getSelectedRows());
  }

  onRestoreRows(): void {
    if (this.rowTypecontrol.valid) {
      const rows = this.rowTypecontrol.value as string === 'modified' ? this.dikeGrid.edition.modifiedRows :
        this.dikeGrid.edition.removedRows;

      this.dikeGrid.edition.restoreRows(rows);
    }
  }

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

  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 %}
