# In-line Filters

## Live example

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

## Enabling In-line Filters

To enable the In-line Filters, you must provide an input property named <mark style="color:orange;">`allowRowFiltering`</mark> at grid scope.

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

```markup
<dike-grid id="grid-filter-types" height="600px" #grid="dkgGrid"
    [allowRowFiltering]="gridProperties.allowRowFilter">
</dike-grid>
```

{% endcode %}

Open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) and click on the **Row Filter** checkbox of the **Filtering** group.

![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)

{% hint style="info" %}
You do not have to define every column as filterable to enable the In-line filters.
{% endhint %}

![Enabling In-line Filters](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FLYMRHA8PxSiYZ7Gcc0t1%2Fin-line-filters-enabling.png?alt=media\&token=ff64bd48-1b4f-4efd-bd1d-f2fbf85d1d2f)

As you can see, the DikeGrid shows a textbox for every defined column. Thus, In-line filters are the **quickest** and **easiest** way to enable filtering.

When you enable the In-line Filters, the DikeGrid registers them automatically, appending the suffix ***row-filter*** to the column id.

![In-line Filters registration](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FOYl9Fcbh6dWnByZ3bNEF%2Fin-line-filters-register.png?alt=media\&token=50582501-3693-47e6-816a-fade69388af1)

When you hide In-line Filters, the DikeGrid removes them automatically, as well.

![In-line Filters deregistration](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Fxt5Xg5Yhjkai1P8SL1g3%2Fin-line-filters-deregister.png?alt=media\&token=21f44d9a-b138-4a0f-bc09-298fd5c94d27)

{% hint style="success" %}
Open the **dev console** to see the `registerFilterableChange` and `deregisterFilterableChange` events output.
{% endhint %}

## Customizing the In-line Filters row

You can change the row's **height** where the DikeGrid shows the In-line Filters.

{% hint style="info" %}
For further details, see the [Grid Structure - Row Filter](https://docs.dikesoft.com/fundamentals/grid-structure/row-filter#changing-the-row-filter-row-height) section.
{% endhint %}

## In-line Filters conditions

By definition, In-line Filters only have **one filter condition**. The following table shows the filter type and its corresponding default condition:

| Filter type         | Default condition |
| ------------------- | ----------------- |
| `Text` and `Binary` | Contains          |
| `Numeric`           | Equals            |
| `Date`              | Equals            |

{% hint style="info" %}
Be aware that **Binary** Filters become **Text** Filters.
{% endhint %}

## Customizing conditions

You can change the condition of the in-line Filters in two ways: by providing an **Injection Token** or for a specific **grid** instance.

### Customization by providing an Injection Token

To change the default condition, you must provide the corresponding custom instance to the following Injection Tokens:

| Injection Token                                                         | Custom instance                                                                                                                                                                         |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <mark style="color:blue;">`CUSTOM_ROW_TEXT_FILTER_CONDITIONS`</mark>    | [<mark style="color:green;">`CustomRowTextCaseFilterCondition`</mark>](https://docs.dikesoft.com/reference/classes/filtering#customrowtextcasefiltercondition-less-than-t-greater-than) |
| <mark style="color:blue;">`CUSTOM_ROW_NUMERIC_FILTER_CONDITIONS`</mark> | [<mark style="color:green;">`CustomRowNumericFilterCondition`</mark>](https://docs.dikesoft.com/reference/classes/filtering#customrownumericfiltercondition-less-than-t-greater-than)   |
| <mark style="color:blue;">`CUSTOM_ROW_DATE_FILTER_CONDITIONS`</mark>    | [<mark style="color:green;">`CustomRowDateFilterCondition`</mark>](https://docs.dikesoft.com/reference/classes/filtering#customrowdatefiltercondition-less-than-t-greater-than)         |

Let us define a condition for `Text` In-line Filters.

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

```typescript
@NgModule({
  providers: [
    {
      provide: CUSTOM_ROW_TEXT_FILTER_CONDITIONS,
      useFactory: (): CustomRowTextCaseFilterCondition<Employee> =>
        new CustomRowTextCaseFilterCondition<Employee>()
          .addExistingCondition(ConditionType.ENDS_WITH)
    }
  ]
})
export class FilteringModule { }

```

{% endcode %}

With the previous code snippet, we have changed the default condition to be **Ends With** for `Text` In-line Filters.

{% hint style="warning" %}
If you add more than one condition to the custom instance, the DikeGrid will take only the first one.
{% endhint %}

### Customization at the grid level

When you provide an Injection Token, you are changing conditions for all DikeGrid instances that live under the place you give the Injection Token.

Sometimes, you want to be specific for a particular DikeGrid instance. Then, to change conditions at the grid scope, you must provide the corresponding custom instance through an input property named <mark style="color:orange;">`gridCustomFilterConditions`</mark>.

{% hint style="info" %}
The <mark style="color:orange;">`gridCustomFilterConditions`</mark> property is of type [<mark style="color:green;">`DikeGridCustomFilterConditions`</mark>](https://docs.dikesoft.com/reference/type-aliases/filtering#dikegridcustomfilterconditions-less-than-t-greater-than). You **can not change** this property at **runtime**.
{% endhint %}

Let us provide custom conditions for `Date` and `Numeric` types.

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

```markup
<dike-grid id="grid-filter-types" height="600px" #grid="dkgGrid"
    [gridCustomFilterConditions]="gridCustomConditions">
</dike-grid>
```

{% endtab %}

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

```typescript
ngOnInit(): void {
    //...
    
    // Defining filters at DikeGrid instance level:
    this.gridCustomConditions = {
      customRowDateFilterConditions: new CustomRowDateFilterCondition<Employee>()
        .addExistingCondition(ConditionType.GREATER_THAN),

      customRowNumericFilterConditions: new CustomRowNumericFilterCondition<Employee>()
        .addCondition({
          text: 'Custom Row Numeric',
          value: 'grid-customRowNumericMultipleOf',
          eval: (entry: Employee, dataColumnDef: DikeDataColumnDef<Employee, number>, values?: DikeNumericFilter): boolean =>
            dataColumnDef.getValue(entry) % values.value1 === 0
        })
    };
  }
```

{% endtab %}
{% endtabs %}

We have changed the `Date` condition to be **Greater Than** and the `Numeric` condition to be **grid-customRowNumericMultipleOf**.

For `Date` types, we took an existing condition, and for `Numeric` types, we defined a new custom condition.

## Summary

In-line Filters are the **quickest** and **easiest** way to enable filtering. Every filter type has a default condition attached, but you can change it by providing a custom condition definition.

### Complete code for this section.

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

```markup
<div class="mt-2 flex flex-row flex-wrap items-center justify-around">
    <button mat-raised-button
        class="flex-none w-56 my-2"
        color="primary"
        (click)="onGetFilterables()">Filterables
    </button>

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

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

    [allowRowFiltering]="gridProperties.allowRowFilter"
    [allowSorting]="gridProperties.allowSorting"
    [allowPagination]="gridProperties.allowPagination"

    (registerFilterableChange)="onRegisterChange($event)"
    (deregisterFilterableChange)="onDeregisterChange($event)"
    (filterChange)="onFilterChange($event)"
    [gridCustomFilterConditions]="gridCustomConditions"

    [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>
        </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-column
        fieldName="age"
        headerText="Age"
        dataType="Numeric"
        contentAlign="center"
        width="100"
        sortable>
    </dike-grid-column>

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

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

</dike-grid>
```

{% endtab %}

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

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

import { DikeGridComponent, DikeGridDataSourceInput, DikeFilterable, DikeGridCustomFilterConditions,
    CustomRowDateFilterCondition, DikeDataColumnDef, CustomRowNumericFilterCondition,
    DikeNumericFilter, ConditionType
} 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: 'in-line-filters',
  templateUrl: './in-line-filters.component.html',
  styleUrls: ['./in-line-filters.component.scss'],

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

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;
  gridCustomConditions: DikeGridCustomFilterConditions<Employee>;

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

    // Defining filters at DikeGrid instance level:
    this.gridCustomConditions = {
      customRowDateFilterConditions: new CustomRowDateFilterCondition<Employee>()
        .addExistingCondition(ConditionType.GREATER_THAN),

      customRowNumericFilterConditions: new CustomRowNumericFilterCondition<Employee>()
        .addCondition({
          text: 'Custom Row Numeric',
          value: 'grid-customRowNumericMultipleOf',
          eval: (entry: Employee, dataColumnDef: DikeDataColumnDef<Employee, number>, values?: DikeNumericFilter): boolean =>
            dataColumnDef.getValue(entry) % values.value1 === 0
        })
    };
  }

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

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

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