New to Kendo UI for Angular? Start a free 30-day trial

Angular Grid Filter Menu

The Grid enables you to embed a drop-down filter menu in each column header. To add a filter menu to the Grid, set filterable to menu.

The following example demonstrates the default filter menu of the Grid.

Example
View Source
Change Theme:

Built-in Filter-Menu Components

If you want to change the default appearance of any default filter menu UI, the FilterMenuTemplateDirective comes handy.

The Grid package provides default filter menu UI components for the most common data types—string, number, Date, and boolean. These components are useful when you apply specific configurations to the default filter menu UI, modify the filter operators, and so on.

The following ready-for-use components are available for the FilterMenuTemplateDirective:

All built-in filter menu components require you to bind the column, filter, and filterService input options to the respective template context properties.

<kendo-grid-column field="ProductName" title="Product Name">
    <ng-template kendoGridFilterMenuTemplate let-filter let-column="column" let-filterService="filterService">
      <kendo-grid-string-filter-menu [column]="column" [filter]="filter" [filterService]="filterService">
      </kendo-grid-string-filter-menu>
    </ng-template>
</kendo-grid-column>

The built-in filter menu components enable you to utilize the available configuration options and customize the filter settings of the Grid at the same time.

Default Filter Operator

The default operators for the built-in filter menu components are:

ComponentDefault Operator
kendo-grid-string-filter-menu"contains"
kendo-grid-numeric-filter-menu"eq"
kendo-grid-boolean-filter-menu"eq"
kendo-grid-date-filter-menu"gte"

If operator is set to "", the Grid will use the first operator from the defined list of operators as its default operator.

You can override the default filter operator by setting the operator property of the built-in filter menu components.

<kendo-grid-column field="ProductName" title="Product Name">
    <ng-template kendoGridFilterMenuTemplate let-filter let-column="column" let-filterService="filterService">
        <kendo-grid-string-filter-menu
            [column]="column"
            [filter]="filter"
            [filterService]="filterService"
            operator="startswith">
                <kendo-filter-startswith-operator></kendo-filter-startswith-operator>
                <kendo-filter-eq-operator></kendo-filter-eq-operator>
        </kendo-grid-string-filter-menu>
    </ng-template>
</kendo-grid-column>

The following example demonstrates how to configure a string filter with a default startswith operator.

Example
View Source
Change Theme:

Order of Filter Operators

You can manually fine-tune the order and number of available operators by declaring the desired operator components in the template.

<kendo-grid-column field="ProductName" title="Product Name">
    <ng-template kendoGridFilterMenuTemplate let-filter let-column="column" let-filterService="filterService">
        <kendo-grid-string-filter-menu
            [column]="column"
            [filter]="filter"
            [filterService]="filterService">
                <kendo-filter-contains-operator></kendo-filter-contains-operator>
                <kendo-filter-eq-operator></kendo-filter-eq-operator>
        </kendo-grid-string-filter-menu>
    </ng-template>
</kendo-grid-column>

The following example demonstrates how to set the order of operators.

Example
View Source
Change Theme:

Custom Filters

The filter menu template also allows you to add any custom content—HTML elements and/or Angular components. This feature is especially useful for scenarios in which the configuration options of the built-in filter menu components are not sufficient to achieve the desired result.

The following steps demonstrate how to implement a custom multi-select filter.

  1. Add a template tag with the kendoGridFilterMenuTemplate directive for the CategoryID column. Inside the template tag, place the MultiSelect component. Notice that the value of the MultiSelect component is composed from the provided filter descriptors through a custom pipe.

    <kendo-grid-column field="CategoryID" title="Category" [width]="180">
        <ng-template kendoGridFilterMenuTemplate
            let-column="column"
            let-filter="filter"
            let-filterService="filterService"
            >
            <kendo-multiselect
                style="width:220px"
                [data]="categories"
                textField="CategoryName"
                valueField="CategoryID"
                [valuePrimitive]="true"
                [value]="filter | filterValues"
                (valueChange)="categoryChange($event, filterService)"
                >
            </kendo-multiselect>
       </ng-template>
       ...
    </kendo-grid-column>
  2. Handle the MultiSelect valueChange event and set the filter descriptor through the filterService instance.

    public categoryChange(values: string[], filterService: FilterService): void {
        filterService.filter({
            filters: values.map(value => ({
                field: "CategoryID",
                operator: "eq",
                value
            })),
            logic: "or"
        });
    }

The following example demonstrates the full implementation of this approach.

Example
View Source
Change Theme:

Custom Filter Menu Components

You can also create custom filter components and use them within the FilterMenuTemplateDirective. This scenario is suitable when the content of the FilterMenuTemplateDirective must be extracted to a component that can be reused in multiple Grid columns as well as across multiple Grid instances throughout the application.

To implement a reusable filter menu component in the Grid:

  1. Create a custom component that will take the filter of the current column and the Grid FilterService as inputs, and place it within the FilterMenuTemplateDirective.

    <kendo-grid-column field="ProductName" title="Product Name" [width]="200">
        <ng-template kendoGridFilterMenuTemplate
            let-filter="filter"
            let-filterService="filterService">
            <my-custom-filter-menu-component
                [currentFilter]="filter"
                [filterService]="filterService">
            </my-custom-filter-menu-component>
        </ng-template>
    </kendo-grid-column>
  2. Use the passed filter value in the custom component to sync the filtering component value with the currently applied filter for the column.

  3. Within the custom filter-menu component, on a user-defined event (typically the component's value change event), update the Grid filters by passing a CompositeFilterDescriptor to the filter()'FilterService` instance.

Custom DropDownList Filter Menu Component

  1. Create a custom component that will take the filter of the current column and the FilterService as inputs and place it within the FilterMenuTemplateDirective.

    <kendo-grid-column field="ProductName" title="Product Name" [width]="200">
        <ng-template kendoGridFilterMenuTemplate
            let-column="column"
            let-filter="filter"
            let-filterService="filterService"
            >
            <dropdownlist-filter
                [isPrimitive]="true"
                [field]="column.field"
                [currentFilter]="filter"
                [filterService]="filterService"
                [textField]="column.field"
                [valueField]="column.field"
                [data]="distinctPrimitive(column.field)">
            </dropdownlist-filter>
        </ng-template>
    </kendo-grid-column>
  2. Set the value of the DropDownList.

    public ngAfterViewInit(): void {
        this.currentData = this.data;
        const currentColumnFilter: FilterDescriptor =
            this.currentFilter.filters.find(
                (filter: FilterDescriptor) => filter.field === this.field
            );
        if (currentColumnFilter) {
            this.value = currentColumnFilter.value;
        }
    }
  3. Set the current column filter by calling the filter() function of the filterService.

    public onValueChange(value: number): void {
        const myFilter: CompositeFilterDescriptor = {
            filters: [{ field: this.field, operator: 'eq', value: value }],
            logic: 'and',
        };
        this.filterService.filter(myFilter);
    }

The following example demonstrates how to create reusable Filter Menu component that contains a DropDownList.

Example
View Source
Change Theme:

Multi-Checkbox Menu Filtering

To create a custom multi-checkbox menu component and use it in the FilterMenu template of the Grid:

  1. Create a custom component that will take the filter of the current column and the FilterService as inputs. Use a collection of the distinct Grid records for the respective field as data. The custom filter component can work with both primitive values and complex objects.

    <kendo-grid-column field="ProductName" title="Product Name">
      <ng-template kendoGridFilterMenuTemplate
            let-column="column"
            let-filter="filter"
            let-filterService="filterService"
            >
            <multicheck-filter
              [isPrimitive]="true"
              [field]="column.field"
              [filterService]="filterService"
              [currentFilter]="filter"
              [data]="distinctPrimitive(column.field)"></multicheck-filter>
        </ng-template>
    </kendo-grid-column>
  2. Loop through the data to create a list of items with checkboxes and text. The items will correspond to the values of the respective Grid column. Attach the required handlers and bindings that will manage the selection and deselection of items.

    <ul>
        <li *ngIf="showFilter">
            <input class="k-textbox k-input k-rounded-md" (input)="onInput($event)" />
        </li>
        <li
            *ngFor="let item of currentData; let i = index;"
            (click)="onSelectionChange(isPrimitive ? item : item[valueField])"
            [ngClass]="{'k-selected': isItemSelected(item)}">
            <input
            type="checkbox"
            id="chk-{{isPrimitive ? item : item[valueField]}}"
            [checked]="isItemSelected(item)" />
            <label
            class="k-multiselect-checkbox k-checkbox-label"
            for="chk-{{isPrimitive ? item : item[valueField]}}">
                {{ isPrimitive ? item : item[textField] }}
            </label>
        </li>
    </ul>
  3. Monitor the selected items and call the filterService.filter() method accordingly.

    public onSelectionChange(item) {
        if(this.value.some(x => x === item)) {
            this.value = this.value.filter(x => x !== item);
        } else {
            this.value.push(item);
        }
    
        this.filterService.filter({
            filters: this.value.map(value => ({
                field: this.field,
                operator: 'eq',
                value
            })),
            logic: 'or'
        });
    }
  4. (Optional) Add a filtering feature for the list of options.

    <li *ngIf="showFilter">
        <input class="k-textbox k-input k-rounded-md" (input)="onInput($event)" />
    </li>
    public onInput(e) {
        this.currentData = distinct([
        ...this.currentData.filter(dataItem => this.value.some(val => val === this.valueAccessor(dataItem))),
        ...filterBy(this.data, {
            operator: 'contains',
            field: this.textField,
            value: e.target.value
        })],
        this.textField
        );
    }

The following example demonstrates the full implementation of the described approach.

Example
View Source
Change Theme:

Filter Menu with Popup

By default, the filter menu closes when the user clicks outside the menu container. This leads to undesired behavior when using components that open their own popups in the body or the root component—for example, the DatePicker. Clicking in the DatePicker's calendar popup will close the Grid filter menu.

To avoid this, override the default behavior and prevent the menu from closing by injecting the SinglePopupService into the current filter component. Then prevent its onClose event.

The following example demonstrates the suggested approach.

Example
View Source
Change Theme: