# Column Filters

## Live example

{% hint style="success" %}
[Column Filters](https://demos.dikesoft.com/dk-grid/filtering/column-filters) live example.
{% endhint %}

## Defining a column as filterable

If you want to filter the DikeGrid rows by a column, you must provide an input property named <mark style="color:orange;">`filterable`</mark> for that column definition.

Consider the following column definitions:

{% tabs %}
{% tab title="column-filters.component.html" %}

```markup
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid"
    (gridColumnDefInstance)="onColumnDefInstance($event)">
    
    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        order="1"
        sortable>
    </dike-grid-column>

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

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

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

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

```

{% endtab %}

{% tab title="column-filters.component.ts" %}

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

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColumnFiltersComponent implements OnInit, OnDestroy {

  onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
    // Define the Age column:
    const ageColumn = new DikeNumericColumnDef<Employee>('age', 'Age');
    ageColumn.order = 4;
    ageColumn.width = 100;
    ageColumn.sortable = true;
    ageColumn.filterable = true;

    // Define the Hire Date column:
    const hireDateColumn = new DikeDateColumnDef<Employee>('hireDate', 'Hire Date');
    hireDateColumn.order = 5;
    hireDateColumn.width = 120;
    hireDateColumn.sortable = true;
    hireDateColumn.filterable = true;

    // Define the Email column:
    const emailColumn = new DikeTextColumnDef<Employee>('email', 'Email');
    emailColumn.order = 6;
    emailColumn.width = 250;
    emailColumn.sortable = true;

    // Then, add the colums to the DikeGridComponent instance:
    columnDef.addColumns([ ageColumn, hireDateColumn, emailColumn ]);
  }
}
```

{% endtab %}
{% endtabs %}

As you can see, we defined the columns **Name**, **Age**, and **Hire Date** as **filterable**.

If you open the [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu) for a **filterable** column, you will see the filter option available.

![Column Context Menu - Fitler option](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FZa7lVPNvjDbt2bgenZQk%2Fcolumn-filters-column-context-menu.png?alt=media\&token=973d64ac-3ebd-43e1-b412-e93c20252ba7)

{% hint style="warning" %}
You can not define a **column group** as filterable.
{% endhint %}

## Initial filter

You can set an initial filter when defining a column.

See the following code:

{% tabs %}
{% tab title="column-filters.component.html" %}

```markup
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid">
    <dike-grid-column
        fieldName="completeNameGroup"
        headerText="Complete Name"
        order="2">

        <dike-grid-column
            fieldName="firstName"
            headerText="Name"
            dataType="Text"
            width="150"
            sortable
            filterable
            [filter]="[{ condition: 'startsWith', logicalOperator: 'and', value: 'w' }]">
        </dike-grid-column>

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

```

{% endtab %}

{% tab title="column-filters.component.ts" %}

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

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColumnFiltersComponent implements OnInit, OnDestroy {

  onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
    // Define the Age column:
    const ageColumn = new DikeNumericColumnDef<Employee>('age', 'Age');
    ageColumn.order = 4;
    ageColumn.width = 100;
    ageColumn.sortable = true;
    ageColumn.filterable = true;
    ageColumn.groupable = true;
    ageColumn.filter = [{
        condition: ConditionType.GREATER_THAN,
        logicalOperator: 'and',
        value1: 50
    }];

    //...

    // Then, add the colums to the DikeGridComponent instance:
    columnDef.addColumns([ ageColumn, hireDateColumn, emailColumn ]);
  }
}

```

{% endtab %}
{% endtabs %}

We have set an initial filter for the **Name** column in the **HTML**. For the **Age** column, we defined the initial filter in **code**.

Open the [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu) for the **Name** or the **Age** column. You will see the filter we have set at creation time.

![Initial filter for the Name column](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FgqtIiraSWa4qOaakbuAF%2Fcolumn-filters-initial-filter.png?alt=media\&token=ad963696-cbdf-4bd4-80cd-3ee92ee2608b)

The type of the object for setting an initial filter depends on the type of the column. For example, the **Age** column is a <mark style="color:red;">`Numeric`</mark> column. Thus, its filter property is of type <mark style="color:green;">`DikeNumericFilter[]`</mark>.

When defining an initial filter in the **HTML** template, the filter property is of type <mark style="color:green;">`DikeFilter[]`</mark>.

{% hint style="success" %}
See the [<mark style="color:green;">`DikeFilter`</mark>](https://docs.dikesoft.com/reference/interfaces/filtering#dikefilter) hierarchy definition.
{% endhint %}

## Modifying filters

You can **add** or **remove** filter conditions for any column defined as **filterable** through the [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu).

Let us add a condition for the **Hire Date** column:

![Adding conditions](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F11yNt8bfQpH91pQZXiuA%2Fcolumn-filters-addding-conditions.gif?alt=media\&token=8b0a192f-d60a-43ca-b08e-f0342152d19c)

{% hint style="info" %}
You can add **any** number of conditions joined by logical operators (**OR**/**AND**).
{% endhint %}

## Filtering execution

### Debounce time

<mark style="color:red;">`Text`</mark> and <mark style="color:red;">`Numeric`</mark> columns have a **debounce time** when the user is typing a value to filter the DikeGrid rows. By default, the debounce time is **400** milliseconds.

![Filtering - Debounce time](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F4gleYMBen6z30nWhGovA%2Fcolumn-filters-debounce-time.gif?alt=media\&token=e5c8d61a-571d-4d64-b4c5-5fc65e8e1ef5)

As you can see, once the time has elapsed, the column sends the filter for its execution.

{% hint style="success" %}
You can change the time you wait for filter execution by providing the Injection Tokens <mark style="color:blue;">`TEXT_FILTER_DEBOUNCE_TIME`</mark> and <mark style="color:blue;">`NUMERIC_FILTER_DEBOUNCE_TIME`</mark>.
{% endhint %}

Let us change the debounce time for `Numeric` types.

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

```typescript
@NgModule({
  providers: [
    { provide: NUMERIC_FILTER_DEBOUNCE_TIME, useValue: 300 }
  ]
})
export class FilteringModule { }

```

{% endcode %}

### Filtering on-demand

If you want to control when to send the filter conditions, you can set a flag at grid scope by providing an input property named <mark style="color:orange;">`onDemandFilter`</mark>.

{% code title="column-filters.component.html" %}

```markup
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid"
    [onDemandFilter]="gridProperties.onDemandFilter">
</dike-grid>
```

{% endcode %}

Since we take the flag value from the `gridProperties` object, please open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) and mark the checkbox **on-demand Filter** under the **Filtering** section.

![Floating Configuration Panel - Filtering](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F2OtUPdlhx9h1L3Hy5gjK%2Fgrid-structure-row-filter-panel-conf.png?alt=media\&token=8812804b-b5eb-492d-b07e-38078fc75f7f)

Open the [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu) for a **filterable** column. Next, you will see the **Filter** button. Click on this button when you have finished defining the filter conditions for the column.&#x20;

![Filtering on-demand](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FL5YFQDOwPS0lwW6Oh14l%2Fcolumn-filters-on-demand.gif?alt=media\&token=1cba49b7-7330-4002-973b-a1c07cdf241c)

## Filtering using the API

You can achieve all the previous tasks by using the corresponding API.&#x20;

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

{% tabs %}
{% tab title="column-filters.component.html" %}

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

{% endtab %}

{% tab title="column-filters.component.ts" %}

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

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColumnFiltersComponent 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 change, at **runtime**, a column definition to be filterable or change its filter conditions.

The following methods belong to the **column API** regarding filtering:

| Method                      | Description                                                                                                   |
| --------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `setColumnFilterablility()` | Use this method to change a column to be **filterable**. You can provide an **initial filter** to be applied. |
| `changeColumnFilter()`      | This method sets the given **filter definition** for the given column.                                        |

{% 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 Filter API

The following methods comprise the **filter API**:

| Method              | Description                                                                                            |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| `clearFilter()`     | This method will **remove** all the filter **conditions** from every filterable.                       |
| `isFilterApplied()` | It returns a **boolean value** indicating if the DikeGrid instance has one filter condition, at least. |
| `getFilteredRows()` | It returns all the **rows** that **meet** all the filter conditions **criteria**.                      |

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

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

{% tabs %}
{% tab title="column-filters.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)="onColumnAsFilterable()">Surname - filterable
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onInitialFilter()">Email - Initial filter
        </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)="onChangeColumnFilter()">Age - Change column filter
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onGetFilterables()">Filterables
        </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)="onGetFilteredRows()">Filtered rows
        </button>

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

<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid">
</dike-grid>

```

{% endtab %}

{% tab title="column-filters.component.ts" %}

```typescript
onColumnAsFilterable(): void {
  // Get the Surname column:
  const surnameColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'lastName');

  // The column exist and is a data column:
  if (!!surnameColumn && isDikeDataColumnDef(surnameColumn)) {
    // Toggle the filterable value:
    this.dikeGrid.columnDef.setColumnFilterability(surnameColumn, !surnameColumn.filterable);
  }
}

onInitialFilter(): 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 filterable value and set an initial filter:
    this.dikeGrid.columnDef.setColumnFilterability(emailColumn, !emailColumn.filterable, [{
      condition: ConditionType.CONTAINS, logicalOperator: 'and', value: '@gmail.com'
    } as DikeTextFilter]);
  }
}

onChangeColumnFilter(): void {
  // Get the age column:
  const ageColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'age');

  // The column exist and is a data column:
  if (!!ageColumn && isDikeDataColumnDef(ageColumn)) {
    // Define the new filter:
    const newFilter: DikeNumericFilter[] = [ { condition: ConditionType.EQUALS, logicalOperator: 'or', value1: 23 } ];
    // Merge the existing filter with the new one:
    const finalFilter: DikeNumericFilter[] = !!ageColumn.filter ? [ ...ageColumn.filter, ...newFilter ] : newFilter;
    // Apply the new filter:
    this.dikeGrid.columnDef.changeColumnFilter(ageColumn, finalFilter);
  }
}

onGetFilterables(): void {
  console.log('Filterables: ', this.dikeGrid.filter.filterables);
}

onGetFilteredRows(): void {
  console.log('Filtered rows: ', this.dikeGrid.filter.getFilteredRows());
}

onClearFilter(): void {
  this.dikeGrid.filter.clearFilter();
}

```

{% endtab %}
{% endtabs %}

The previous definition generates the following output:

![Filtering - Using the API](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FbMAOnIX2TnjCrGCrSBPk%2Fcolumn-filters-using-api.png?alt=media\&token=a842ddad-b942-41d9-bd9c-dbc36171cafd)

In the following list, we describe every button action:

1. **Surname - filterable**. Click on this button to make the **Surname** column filterable or not filterable. It toggles the current filterable value.
2. **Email - Initial filter**. Same as before, it toggles the current filterable value. When the column becomes filterable, the given filter is applied. Otherwise, the DikeGrid instance will ignore the given filter.
3. **Age - Change column filter**. Since the **Age** column is filterable, we change its filter, merging the current condition with the new one. If you click more than once, the action will append the new filter condition to the existing ones.
4. **Filterables**. Clicking on this button will print out, to the **dev console,** the current filterables.
5. **Filtered rows**. Clicking on this button will print out, to the **dev console**, all the rows that meet the filter conditions criteria.
6. **Clear filter**. Clicking on this button will **remove** all the filter conditions.

{% hint style="info" %}
When defining a column as **filterable**, the DikeGrid **registers** that column in an internal **Map** structure named ***filterables***. The items of this Map are of type [<mark style="color:green;">`DikeFilterable`</mark>](https://docs.dikesoft.com/reference/interfaces/filtering#dikefilterable-less-than-t-greater-than).
{% endhint %}

## Filter Events

When defining a column as **filterable** or **adding/removing** a filter condition, the DikeGrid instance **emits** the related events.

The filter events are:

| Event                        | Description                                                                                                                                                                    |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `registerFilterableChange`   | It emits when you define a column as **filterable**. Then, the DikeGrid instance will add the column to the internal Map named ***filterables***.                              |
| `deregisterFilterableChange` | It emits when you make a column **not filterable** when it was **filterable**. Then, the DikeGrid instance will remove the column to the internal Map named ***filterables***. |
| `filterChange`               | It emits when the user has **defined/changed** a filter condition.                                                                                                             |
| `clearFilterChange`          | It emits after the DikeGrid instance has **removed** all the filter conditions.                                                                                                |

Let us listen to these events:

{% tabs %}
{% tab title="column-filters.component.html" %}

```markup
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid"
    (registerFilterableChange)="onRegisterChange($event)"
    (deregisterFilterableChange)="onDeregisterChange($event)"
    (filterChange)="onFilterChange($event)"
    (clearFilterChange)="onClearFilterChange()">
</dike-grid>
```

{% endtab %}

{% tab title="column-filters.component.ts" %}

```typescript
onRegisterChange(filterable: DikeFilterable<Employee>): void {
  console.log('Register change: ', filterable);
}

onDeregisterChange(filterable: DikeFilterable<Employee>): void {
  console.log('Deregister change: ', filterable);
}

onFilterChange(filterable: DikeFilterable<Employee>): void {
  console.log('Filter change: ', filterable);
}

onClearFilterChange(): void {
  console.log('Clear filter - filterables: ', this.dikeGrid.filter.filterables);
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
Please, open your **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;">`DikeGridFilter`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridfilter#events) instance.
{% endhint %}

## Row Grouping and Filtering

When grouping the DikeGrid rows by a column and filtering those rows, you will see the **filter icon** on the right side of the **group** name showing how many data rows for that group have met the filter criteria.

We have **allowed Row-Grouping**, and we have defined the Age column as **groupable**.

{% tabs %}
{% tab title="column-filters.component.html" %}

```markup
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid"
    allowRowGrouping
    [allowColumnDragging]="gridProperties.allowColumnDragging">
</dike-grid>
```

{% endtab %}

{% tab title="column-filters.component.ts" %}

```typescript
onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
    // Define the Age column:
    const ageColumn = new DikeNumericColumnDef<Employee>('age', 'Age');
    ageColumn.order = 4;
    ageColumn.width = 100;
    ageColumn.sortable = true;
    ageColumn.filterable = true;
    ageColumn.groupable = true;
    ageColumn.draggable = true;
    ageColumn.filter = [{
        condition: ConditionType.GREATER_THAN,
        logicalOperator: 'and',
        value1: 50
    }];
    
    //...
}
```

{% endtab %}
{% endtabs %}

![Filtering and Row Grouping](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Ff4HzaT8xp5IT6MQBnp79%2Fcolumn-filters-row-grouping.gif?alt=media\&token=a3dbe12b-facc-4223-91e4-a9b96d8680fb)

If you **group** the DikeGrid rows by a column with filters, the DikeGrid will **ignore** those filters.&#x20;

![Row-Grouping ignores the filters](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FuCTCfNKLcdKqq6qscOHD%2Fcolumn-filters-row-grouping-ignores-filters.gif?alt=media\&token=677a4f76-3c71-4a5f-af15-f648c08221fb)

As you can see in the previous output, the DikeGrid **ignores** the filter when **grouping** the DikeGrid rows by the **Age** column despite defining a filter for this column. As a result, the DikeGrid shows all the values for the **Age** column as **groups**.

## Summary

It is enough to define a column as **filterable** to give the user the ability to filter the DikeGrid rows. The user can add any number of filter conditions. By default, `Text` and `Numeric` filter types have a **debounce time**, but you can change this value or send filters **on-demand**.

You can use the **column API** and the **filter API** to perform filtering tasks. All the filter actions emit their corresponding **event**.

### Complete code for this section.

{% tabs %}
{% tab title="column-filters.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)="onColumnAsFilterable()">Surname - filterable
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onInitialFilter()">Email - Initial filter
        </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)="onChangeColumnFilter()">Age - Change column filter
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onGetFilterables()">Filterables
        </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)="onGetFilteredRows()">Filtered rows
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            (click)="onClearFilter()">Clear filter
        </button>
    </div>
</div>
<dike-grid id="grid-col-filters" height="600px" #grid="dkgGrid"
    [displayRowId]="gridProperties.displayRowId"
    [gridElevation]="gridProperties.matElevation"
    [gridElevationValue]="gridProperties.elevationValue"
    [striped]="gridProperties.stripeRows"
    [verticalRowLines]="gridProperties.verticalRowLines"

    allowRowGrouping
    [allowColumnDragging]="gridProperties.allowColumnDragging"
    [allowSorting]="gridProperties.allowSorting"
    [onDemandFilter]="gridProperties.onDemandFilter"

    (registerFilterableChange)="onRegisterChange($event)"
    (deregisterFilterableChange)="onDeregisterChange($event)"
    (filterChange)="onFilterChange($event)"
    (clearFilterChange)="onClearFilterChange()"

    (gridColumnDefInstance)="onColumnDefInstance($event)"
    [datasource]="dkgDataSource">

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        order="1"
        sortable>
    </dike-grid-column>
    
    <dike-grid-column
        fieldName="completeNameGroup"
        headerText="Complete Name"
        order="2">

        <dike-grid-column
            fieldName="firstName"
            headerText="Name"
            dataType="Text"
            width="150"
            sortable
            filterable
            [filter]="[{ condition: 'startsWith', logicalOperator: 'and', value: 'w' }]">
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            sortable>
        </dike-grid-column>
    </dike-grid-column>
    
    <dike-grid-column
        fieldName="gender"
        headerText="Gender"
        dataType="Binary"
        width="110"
        order="3"
        sortable>
    </dike-grid-column>
    
</dike-grid>    
```

{% endtab %}

{% tab title="column-filters.component.ts" %}

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

import { ConditionType, DikeDateColumnDef, DikeFilterable, DikeGridColumnDef, DikeGridComponent, DikeGridDataSourceInput,
    DikeNumericColumnDef, DikeNumericFilter, DikeTextColumnDef, DikeTextFilter, 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: 'column-filters',
  templateUrl: './column-filters.component.html',
  styleUrls: ['./column-filters.component.scss'],

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

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

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

  onColumnDefInstance(columnDef: DikeGridColumnDef<Employee>): void {
    // Define the Age column:
    const ageColumn = new DikeNumericColumnDef<Employee>('age', 'Age');
    ageColumn.order = 4;
    ageColumn.width = 100;
    ageColumn.sortable = true;
    ageColumn.filterable = true;
    ageColumn.groupable = true;
    ageColumn.draggable = true;
    ageColumn.filter = [{
        condition: ConditionType.GREATER_THAN,
        logicalOperator: 'and',
        value1: 50
    }];

    // Define the Hire Date column:
    const hireDateColumn = new DikeDateColumnDef<Employee>('hireDate', 'Hire Date');
    hireDateColumn.order = 5;
    hireDateColumn.width = 120;
    hireDateColumn.sortable = true;
    hireDateColumn.filterable = true;

    // Define the Email column:
    const emailColumn = new DikeTextColumnDef<Employee>('email', 'Email');
    emailColumn.order = 6;
    emailColumn.width = 250;
    emailColumn.sortable = true;

    // Then, add the colums to the DikeGridComponent instance:
    columnDef.addColumns([ ageColumn, hireDateColumn, emailColumn ]);
  }

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

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

  onColumnAsFilterable(): void {
    // Get the Surname column:
    const surnameColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'lastName');

    // The column exist and is a data column:
    if (!!surnameColumn && isDikeDataColumnDef(surnameColumn)) {
      // Toggle the filterable value:
      this.dikeGrid.columnDef.setColumnFilterability(surnameColumn, !surnameColumn.filterable);
    }
  }

  onInitialFilter(): 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 filterable value and set an initial filter:
      this.dikeGrid.columnDef.setColumnFilterability(emailColumn, !emailColumn.filterable, [{
        condition: ConditionType.CONTAINS, logicalOperator: 'and', value: '@gmail.com'
      } as DikeTextFilter]);
    }
  }

  onChangeColumnFilter(): void {
    // Get the age column:
    const ageColumn = this.dikeGrid.columnDef.findColumn(column => column.fieldName === 'age');

    // The column exist and is a data column:
    if (!!ageColumn && isDikeDataColumnDef(ageColumn)) {
      // Define the new filter:
      const newFilter: DikeNumericFilter[] = [ { condition: ConditionType.EQUALS, logicalOperator: 'or', value1: 23 } ];
      // Merge the existing filter with the new one:
      const finalFilter: DikeNumericFilter[] = !!ageColumn.filter ? [ ...ageColumn.filter, ...newFilter ] : newFilter;
      // Apply the new filter:
      this.dikeGrid.columnDef.changeColumnFilter(ageColumn, finalFilter);
    }
  }

  onGetFilterables(): void {
    console.log('Filterables: ', this.dikeGrid.filter.filterables);
  }

  onGetFilteredRows(): void {
    console.log('Filtered rows: ', this.dikeGrid.filter.getFilteredRows());
  }

  onClearFilter(): void {
    this.dikeGrid.filter.clearFilter();
  }

  onRegisterChange(filterable: DikeFilterable<Employee>): void {
    console.log('Register change: ', filterable);
  }

  onDeregisterChange(filterable: DikeFilterable<Employee>): void {
    console.log('Deregister change: ', filterable);
  }

  onFilterChange(filterable: DikeFilterable<Employee>): void {
    console.log('Filter change: ', filterable);
  }

  onClearFilterChange(): void {
    console.log('Clear filter - filterables: ', this.dikeGrid.filter.filterables);
  }

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

```

{% endtab %}

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

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

import { DikeDataGridModule, NUMERIC_FILTER_DEBOUNCE_TIME,
    CUSTOM_ROW_TEXT_FILTER_CONDITIONS, CustomRowTextCaseFilterCondition, ConditionType,
    CUSTOM_TEXT_FILTER_CONDITIONS, CustomTextCaseFilterCondition,
    DikeDataColumnDef, DikeTextFilter } from '@dikesoft/angular-data-grid';

import { SharedModule } from 'app/shared/shared.module';
import { Employee } from 'app/mock-api/common/employees/data.model';
import { filteringRoutes } from 'app/modules/admin/filtering/filtering.routing';

import { ColumnFiltersComponent } from './column-filters/column-filters.component';
import { FilterTypesComponent } from './filter-types/filter-types.component';
import { InLineFiltersComponent } from './in-line-filters/in-line-filters.component';

@NgModule({
  declarations: [
    ColumnFiltersComponent,
    FilterTypesComponent,
    InLineFiltersComponent
  ],
  imports: [
    CommonModule,
    RouterModule.forChild(filteringRoutes),

    SharedModule,
    DikeDataGridModule
  ],
  providers: [
    { provide: NUMERIC_FILTER_DEBOUNCE_TIME, useValue: 300 },
    {
      provide: CUSTOM_ROW_TEXT_FILTER_CONDITIONS,
      useFactory: (): CustomRowTextCaseFilterCondition<Employee> =>
        new CustomRowTextCaseFilterCondition<Employee>()
          .addExistingCondition(ConditionType.ENDS_WITH)
    },
    {
      provide: CUSTOM_TEXT_FILTER_CONDITIONS,
      useFactory: (): CustomTextCaseFilterCondition<Employee> =>
        new CustomRowTextCaseFilterCondition()
          .addCondition({
            text: 'Custom Lower Case',
            value: 'global-customLowerCaseText',
            eval: (entry: Employee, dataColumnDef: DikeDataColumnDef<Employee, string>, values?: DikeTextFilter): boolean =>
              dataColumnDef.getValue(entry).toLowerCase().includes(values.value)
          })
    }
  ]
})
export class FilteringModule { }

```

{% endtab %}
{% endtabs %}
