# Row Selection

## Live example

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

## Allowing the selection operation

To allow the user to **select/deselect** the DikeGrid rows, you must provide an input property named <mark style="color:orange;">`allowSelection`</mark>. This property is at the grid scope.

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid"
    [allowSelection]="gridProperties.allowSelection">
</dike-grid>
```

{% endcode %}

{% hint style="info" %}
You can change the value of the <mark style="color:orange;">`allowSelection`</mark> property at **runtime**.
{% endhint %}

Open the [Floating Configuration Panel](/overview.md#floating-configuration-panel) for the live example and click on the **Allow Selection** checkbox.

![Floating Configuration Panel - Selection](/files/uDSww5k0jG0ltAlSYNt6)

Once you have enabled selection, you will see a **checkbox** column displayed for every row. To **select/deselect** a row, click on the related checkbox.

![Enabling Row Selection](/files/QQCdJIEGLrw2BGs1BZKS)

## Selectable rows

By default, when you enable selection for the DikeGrid, all rows are susceptible to being selected.

If you want the user can select only **some rows**, you can provide a **function** specifying the conditions the rows must meet. You can set this function by providing a property named <mark style="color:orange;">`selectableRows`</mark>.

Let us define this function to allow the user to select rows whose age value is not 27.

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid"
    [selectableRows]="selectableRowsDefinition">
</dike-grid>
```

{% endtab %}

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

```typescript
selectableRowsDefinition(entry: Employee): boolean {
    // Allow selection only for those rows whose age value is different of 27:
    return entry.age !== 27;
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
The <mark style="color:orange;">`selectableRows`</mark> property is of type [<mark style="color:green;">`SelectableFn`</mark>](/reference/dkgrid-api/dkgridselection.md#properties), and you can also provide this function using the **selection API**.
{% endhint %}

{% hint style="info" %}
You can change this function definition at **runtime**. Therefore, the DikeGrid instance will evaluate the currently selected rows, deselecting those rows that do not meet the new criteria.
{% endhint %}

As you can see, rows that do not meet the defined criteria display their checkbox **disabled**.

![Defining the selectableRows function](/files/7I7p9Xqi1Cn7CzcRcihr)

## Header Checkbox Selection

When you provide an **in-memory** data set, the DikeGrid instance always shows a checkbox in its header.

On the other hand, the DikeGrid instance will not show a checkbox in its header when you provide a **custom Datasource** because the DikeGrid does not know the total length of the provided data set.

{% hint style="success" %}
See the [Datasource](/fundamentals/datasource.md) section for further details about an **in-memory** data set and a **custom Datasource**.
{% endhint %}

By default, the checkbox in the header will select all rows even though the data set is filtered. However, if you want to select only the filtered rows, you can use the **selection API**.

## Group Selection

When you group rows by a column, every group will show its checkbox.

1. The selectable rows under the group will be selected when you click on the checkbox in the group. If the group has **non-selectable** rows, its state will be **indeterminate**.
2. When you click in any of the rows under the group, the checkbox in the group will update its status to indeterminate and become checked until you select all rows.

{% hint style="info" %}
The checkbox in the header will update its state as well.
{% endhint %}

We have enabled **row grouping** in the live demo to see this feature.

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid"
    allowRowGrouping
    allowRowFiltering
    allowColumnDragging>
    
    <dike-grid-column
        fieldName="gender"
        headerText="Gender"
        dataType="Binary"
        width="130"
        draggable
        groupable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="age"
        headerText="Age"
        dataType="Numeric"
        contentAlign="center"
        width="100"
        draggable
        groupable>
    </dike-grid-column>
</dike-grid>
```

{% endcode %}

As you can see, apart from allowing **row grouping**, we have enabled **column dragging**. Then, we set **Gender** and **Age** columns being **groupable**.&#x20;

You can move the **Age** column to the group panel with the previous configuration. Thus, you can select any group or a row under any group.

![Group Selection](/files/g2g42RXI9DMUvDRZr8HL)

## DikeGrid Selection API

You can also use the **selection API** to select rows.

Before using the **selection API**, you must retrieve the related DikeGrid instance by querying the component's view.

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid">
</dike-grid>
```

{% endtab %}

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

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

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

{% endtab %}
{% endtabs %}

The **selection API** has the following methods:

| Method                 | Description                                                                                                                                                                                                            |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `selectOne()`          | <ol><li>It marks the given row as selected. </li><li>The given row must pass the selectable function. </li><li>This method emits the <code>selectionChange</code> and <code>selectedRowChange</code> events.</li></ol> |
| `select()`             | <ol><li>It marks the given rows as selected. </li><li>It emits the <code>selectionChange</code> event.</li></ol>                                                                                                       |
| `deselectOne()`        | <ol><li>It turns off the selected flag for the given row.</li><li>This method emits the <code>selectionChange</code> and <code>deselectedRowChange</code> events.</li></ol>                                            |
| `deselect()`           | <ol><li>It turns off the selected flag for the given rows.</li><li>This method emits the <code>selectionChange</code> event.</li></ol>                                                                                 |
| `getSelectedRows()`    | This method returns an array of all selected rows.                                                                                                                                                                     |
| `getSelectedEntries()` | It returns all selected entries.                                                                                                                                                                                       |
| `selectAll()`          | This method will set all rows coming from the data source as selected.                                                                                                                                                 |
| `deselectAll()`        | It turns off the selection flag of all selected rows.                                                                                                                                                                  |
| `resetSelection()`     | This method deselects all selected rows and cleanses some internal variables. The DikeGrid instance will invoke this method every time you provide a new data set.                                                     |

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

{% hint style="info" %}
To use any previous methods, you must have allowed selection by providing the input property named <mark style="color:orange;">`allowSelection`</mark>.
{% endhint %}

Remember, when you provide a data source, the DikeGrid instance **wraps** every entry into an object of type <mark style="color:green;">`DikeGridRowEntry`</mark>. See the class hierarchy for the DikeGrid rows.

To see the **selection API** in action, we have created the following UI:

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

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!isFiltered"
            (click)="onSelect()">select / 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"
            [disabled]="!isFiltered"
            (click)="onDeselectOne()">deselectOne / filtered
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!isFiltered"
            (click)="onDeselect()">deselect / 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)="onGetSelectedRows()">getSelectedRows
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onGetSelectedEntries()">getSelectedEntries
        </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)="onSelectAll()">selectAll
        </button>

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

<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid">
</dike-grid>

```

{% endtab %}

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

```typescript
onSelectOne(): void {
  const filteredRows = this.dikeGrid.filter.getFilteredRows();

  if (filteredRows.length > 0) {
    this.dikeGrid.selection.selectOne(filteredRows[0]);
  }
}

onSelect(): void {
  const filteredRows = this.dikeGrid.filter.getFilteredRows();

  if (filteredRows.length > 0) {
    this.dikeGrid.selection.select(filteredRows);
  }
}

onDeselectOne(): void {
  const selectedFromFiltered = this.dikeGrid.filter.getFilteredRows().filter(row => row.selected);

  if (selectedFromFiltered.length > 0) {
    this.dikeGrid.selection.deselectOne(selectedFromFiltered[0]);
  }
}

onDeselect(): void {
  const filteredRows = this.dikeGrid.filter.getFilteredRows();

  if (filteredRows.length > 0) {
    this.dikeGrid.selection.deselect(filteredRows);
  }
}

onGetSelectedRows(): void {
  console.log('Selected rows: ', this.dikeGrid.selection.getSelectedRows());
}

onGetSelectedEntries(): void {
  console.log('Selected entries: ', this.dikeGrid.selection.getSelectedEntries());
}

onSelectAll(): void {
  this.dikeGrid.selection.selectAll();
}

onDeselectAll(): void {
  this.dikeGrid.selection.deselectAll();
}

```

{% endtab %}
{% endtabs %}

The previous HTML code generates the following output:

![Row Selection using the API](/files/xJqEXYlY2zzpjxf9wcNn)

For every button, we have attached the following actions:

1. Buttons **selectOne / filtered**, **select / filtered**, **deselectOne / filtered** and **deselect / filtered** work over the filtered set. These buttons are enabled if you have filtered the original set.
2. To allow filtering, we enabled the DikeGrid **Row Filter**.
3. The **selectAll** and **deselectAll** buttons are self-explanatory.
4. We printed out the **selected rows** and **selected entries** in the **dev console**.

Please, open the **live demo** and see the previous buttons in action.

To evaluate if the DikeGrid instance has a filter applied, we listen to the `filterChange` and `columnsChange` events.

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid"
    (columnsChange)="onColumnsChange($event)"
    (filterChange)="onFilterChange($event)">
</dike-grid>
```

{% endtab %}

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

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

onColumnsChange(columns: DikeColumnDef[]): void {
  // We ignore the argument columns because we are only interested in the action.
  this.isFiltered = !!this.dikeGrid ? this.dikeGrid.filter.isFilterApplied() : false;
}
```

{% endtab %}
{% endtabs %}

1. The `filterChange` event fires every time the user types something in the DikeGrid **Row Filter**.
2. We listen to the `columnsChange` event because every time the user groups the rows by a column, the user must move that column to the group panel, provoking the DikeGrid instance to raise the `columnsChange` event.

{% hint style="warning" %}
Remember that the DikeGrid ignores filters for the columns in the group panel.
{% endhint %}

## Selection events

Every time we **select** or **deselect** one or more rows, the DikeGrid instance emits the related event.

The following are the selection events:

| Event               | Description                                                |
| ------------------- | ---------------------------------------------------------- |
| `selectedRowChange` | It emits when the user selects one row.                    |
| `deselectRowChange` | It emits when the user deselects one row.                  |
| `selectionChange`   | It emits when the user selects/deselects one or more rows. |

We listen to these three events:

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

```markup
<dike-grid id="grid-row-selection" height="700px" #grid="dkgGrid"
    (selectedRowChange)="onSelectedRowChange($event)"
    (deselectedRowChange)="onDeselectedRowChange($event)"
    (selectionChange)="onSelectionChange($event)">
</dike-grid>
```

{% endtab %}

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

```typescript
onSelectedRowChange(row: DikeGridDataRowEntry<Employee>): void {
  console.log('Select one row change: ', row);
}

onDeselectedRowChange(row: DikeGridDataRowEntry<Employee>): void {
  console.log('Deselect one row change: ', row);
}

onSelectionChange(rows: DikeGridDataRowEntry<Employee>[]): void {
  console.log('Selection change: ', rows);
}
```

{% endtab %}
{% endtabs %}

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

{% hint style="info" %}
You can also listen to these events from the [<mark style="color:green;">`DikeGridSelection`</mark>](/reference/dkgrid-api/dkgridselection.md#events) instance.
{% endhint %}

## Summary

To perform the **selection** operation, you must allow it by providing an input property named <mark style="color:orange;">`allowSelection`</mark>. By default, the user can select all rows, but you can enable only some rows for selection by providing a **custom function** where every row must meet the established criteria. You can **select** or **deselect** rows through the **UI** or the **selection API**.

### Complete code for this section

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

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!isFiltered"
            (click)="onSelect()">select / 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"
            [disabled]="!isFiltered"
            (click)="onDeselectOne()">deselectOne / filtered
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!isFiltered"
            (click)="onDeselect()">deselect / 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)="onGetSelectedRows()">getSelectedRows
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onGetSelectedEntries()">getSelectedEntries
        </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)="onSelectAll()">selectAll
        </button>

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

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

    (columnsChange)="onColumnsChange($event)"
    (filterChange)="onFilterChange($event)"
    (selectedRowChange)="onSelectedRowChange($event)"
    (deselectedRowChange)="onDeselectedRowChange($event)"
    (selectionChange)="onSelectionChange($event)"
    [selectableRows]="selectableRowsDefinition"

    allowRowGrouping
    allowRowFiltering
    allowColumnDragging
    [allowSelection]="gridProperties.allowSelection"
    [datasource]="dkgDataSource">

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

    <dike-grid-column
        fieldName="country"
        headerText="Country"
        dataType="Text"
        width="250">
    </dike-grid-column>

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

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

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

    <dike-grid-column
        fieldName="gender"
        headerText="Gender"
        dataType="Binary"
        width="130"
        draggable
        groupable>
    </dike-grid-column>

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

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

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        width="150">
    </dike-grid-column>

</dike-grid>
```

{% endtab %}

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

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

import { Subscription } from 'rxjs';

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

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

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  isFiltered: boolean;

  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

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

    this.isFiltered = false;
  }

  ngOnInit(): void {
    this.dkgDataSource = this.sampleData.getEmployees(1000);
    // Listening to any config property change:
    this.setChangeGridPropertiesSubscription();
  }

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

  selectableRowsDefinition(entry: Employee): boolean {
    // Allow selection only for those rows whose age value is different of 27:
    return entry.age !== 27;
  }

  onSelectOne(): void {
    const filteredRows = this.dikeGrid.filter.getFilteredRows();

    if (filteredRows.length > 0) {
      this.dikeGrid.selection.selectOne(filteredRows[0]);
    }
  }

  onSelect(): void {
    const filteredRows = this.dikeGrid.filter.getFilteredRows();

    if (filteredRows.length > 0) {
      this.dikeGrid.selection.select(filteredRows);
    }
  }

  onDeselectOne(): void {
    const selectedFromFiltered = this.dikeGrid.filter.getFilteredRows().filter(row => row.selected);

    if (selectedFromFiltered.length > 0) {
      this.dikeGrid.selection.deselectOne(selectedFromFiltered[0]);
    }
  }

  onDeselect(): void {
    const filteredRows = this.dikeGrid.filter.getFilteredRows();

    if (filteredRows.length > 0) {
      this.dikeGrid.selection.deselect(filteredRows);
    }
  }

  onGetSelectedRows(): void {
    console.log('Selected rows: ', this.dikeGrid.selection.getSelectedRows());
  }

  onGetSelectedEntries(): void {
    console.log('Selected entries: ', this.dikeGrid.selection.getSelectedEntries());
  }

  onSelectAll(): void {
    this.dikeGrid.selection.selectAll();
  }

  onDeselectAll(): void {
    this.dikeGrid.selection.deselectAll();
  }

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

  onColumnsChange(columns: DikeColumnDef[]): void {
    // We ignore the argument columns because we are only interested in the action.
    this.isFiltered = !!this.dikeGrid ? this.dikeGrid.filter.isFilterApplied() : false;
  }

  onSelectedRowChange(row: DikeGridDataRowEntry<Employee>): void {
    console.log('Select one row change: ', row);
  }

  onDeselectedRowChange(row: DikeGridDataRowEntry<Employee>): void {
    console.log('Deselect one row change: ', row);
  }

  onSelectionChange(rows: DikeGridDataRowEntry<Employee>[]): void {
    console.log('Selection change: ', rows);
  }

  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/rows/row-selection.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.
