Filtering

To enable the filtering functionality, set the filterable property to true.

Basic Configuration

When the filtering functionality is enabled, the component renders a filter input in the drop-down list. On every character input, the component triggers a onFilterChange event. The event argument contains the typed string value that you can use to filter the source.

import React from 'react';
import ReactDOM from 'react-dom';
import { DropDownList } from '@progress/kendo-react-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

const allData = [
    { id: 1, text: "Small" },
    { id: 2, text: "Medium" },
    { id: 3, text: "Large" }
];

class AppComponent extends React.Component {
    state = {
        data: allData.slice()
    };

    filterChange = (event) => {
        this.setState({
            data: this.filterData(event.filter)
        });
    }

    filterData(filter) {
        const data = allData.slice();
        return filterBy(data, filter);
    }

    render() {
        return (
            <DropDownList
                data={this.state.data}
                textField="text"
                filterable={true}
                onFilterChange={this.filterChange}
            />
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);

To filter the data after a delay, use a similar implementation. You can toggle the loading property and provide the user with a visual indication of the filtering process.

import React from 'react';
import ReactDOM from 'react-dom';
import { DropDownList } from '@progress/kendo-react-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

const allData = [
    { id: 1, text: "Small" },
    { id: 2, text: "Medium" },
    { id: 3, text: "Large" }
];
const delay = 500;

class AppComponent extends React.Component {
    state = {
        data: allData.slice(),
        loading: false
    };

    filterChange = (event) => {
        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
            this.setState({
                data: this.filterData(event.filter),
                loading: false
            });
        }, delay);

        this.setState({
            loading: true
        });
    }

    filterData(filter) {
        const data = allData.slice();
        return filterBy(data, filter);
    }

    render() {
        return (
            <DropDownList
                data={this.state.data}
                textField="text"
                filterable={true}
                onFilterChange={this.filterChange}
                loading={this.state.loading}
            />
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);

Minimum Filter Length

The following example demonstrates how to update the data and open the DropDownList only after typing a minimum number of characters.

import React from 'react';
import ReactDOM from 'react-dom';
import { DropDownList } from '@progress/kendo-react-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

const allData = [
    { id: 1, text: "Small" },
    { id: 2, text: "Medium" },
    { id: 3, text: "Large" }
];

class AppComponent extends React.Component {
    state = { data: allData.slice() };

    filterChange = (event) => {
        const newData = event.filter.value.length > 3 ?
            this.filterData(event.filter) : allData.slice();

        this.setState({
            data: newData
        });
    }

    filterData(filter) {
        const data = allData.slice();
        return filterBy(data, filter);
    }

    render() {
        return (
            <DropDownList
                data={this.state.data}
                textField="text"
                filterable={true}
                onFilterChange={this.filterChange}
            />
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);

Filtering with Remote Data and Virtualization

The following example demonstrates how to configure the DropDownList to use remote data along with data caching, virtual scrolling, and filtering.

import React from 'react';
import ReactDOM from 'react-dom';
import { DropDownList } from '@progress/kendo-react-dropdowns';

const textField = 'ContactName';
const keyField = 'CustomerID';
const defaultItem = { [textField]: 'Select customer...', [keyField]: null };
const emptyItem = { [textField]: 'loading ...' };
const pageSize = 10;

const loadingData = [];
while (loadingData.length < pageSize) {
    loadingData.push({ ...emptyItem });
}

class AppComponent extends React.Component {
    baseUrl = `https://odatasampleservices.azurewebsites.net/V4/Northwind/Northwind.svc/`;
    init = { method: 'GET', accept: 'application/json', headers: [] };
    dataCaching = [];
    pendingRequest;
    requestStarted = false;
    state = {
        data: [],
        value: null,
        skip: 0,
        total: 0,
        filter: ''
    };

    componentDidMount() {
        this.requestData(0, this.state.filter);
    }

    requestData(skip, filter) {
        if (this.requestStarted) {
            clearTimeout(this.pendingRequest);
            this.pendingRequest = setTimeout(() => { this.requestData(skip, filter); }, 50);
            return;
        }

        const url = this.baseUrl +
            `Customers?$filter=contains(ContactName,'${filter}')&$skip=${skip}&$top=${pageSize}&$count=true`;

        this.requestStarted = true;
        fetch(url, this.init)
            .then(response => response.json())
            .then(json => {
                const total = json['@odata.count'];
                const items = [];
                json.value.forEach((element, index) => {
                    const { CustomerID, ContactName } = element;
                    const item = { [keyField]: CustomerID, [textField]: ContactName };
                    items.push(item);
                    this.dataCaching[index + skip] = item;
                });

                if (skip === this.state.skip) {
                    this.setState({
                        data: items,
                        total: total
                    });
                }
                this.requestStarted = false;
            });
    }

    onFilterChange = (event) => {
        const filter = event.filter.value;

        this.resetCach();
        this.requestData(0, filter);

        this.setState({
            data: loadingData,
            skip: 0,
            filter: filter
        });
    }

    pageChange = (event) => {
        const skip = event.page.skip;
        const filter = this.state.filter;

        if (this.shouldRequestData(skip)) {
            this.requestData(skip, filter);
        }

        const data = this.getCachedData(skip);

        this.setState({
            data: data,
            skip: skip
        });
    }

    onChange = (event) => {
        const value = event.target.value;
        if (value && value[textField] === emptyItem[textField]) {
            return;
        }
        this.setState({
            value: value
        });
    }

    render() {
        return (
            <DropDownList
                data={this.state.data}
                value={this.state.value}
                onChange={this.onChange}
                dataItemKey={keyField}
                textField={textField}
                defaultItem={defaultItem}
                filterable={true}
                onFilterChange={this.onFilterChange}
                virtual={{
                    pageSize: pageSize,
                    skip: this.state.skip,
                    total: this.state.total
                }}
                onPageChange={this.pageChange}
                style={{ width: '200px' }}
            />
        );
    }

    componentWillUnmount() {
        this.resetCach();
    }

    shouldRequestData(skip) {
        for (let i = 0; i < pageSize; i++) {
            if (!this.dataCaching[skip + i]) {
                return true;
            }
        }
        return false;
    }

    getCachedData(skip) {
        const data = [];
        for (let i = 0; i < pageSize; i++) {
            data.push(this.dataCaching[i + skip] || { ...emptyItem });
        }
        return data;
    }

    resetCach() {
        this.dataCaching.length = 0;
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);
 /