Filtering

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

Basic Configuration

On every user modification of the input value, the ComboBox triggers an 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 { ComboBox } from '@progress/kendo-react-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

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

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 (
            <ComboBox
                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 { ComboBox } from '@progress/kendo-react-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

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

class AppComponent extends React.Component {
    state = {
        data: allData,
        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 (
            <ComboBox
                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 drop-down list of the ComboBox only after typing a minimum number of characters.

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

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

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 (
            <ComboBox
                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 ComboBox to use remote data along with data caching, virtual scrolling, and filtering.

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

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

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: [],
        skip: 0,
        total: 0,
        value: null,
        filter: ''
    };

    componentDidMount() {
        this.requestData(0, '');
    }

    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 (
            <ComboBox
                data={this.state.data}
                value={this.state.value}
                onChange={this.onChange}
                textField={textField}
                dataItemKey={keyField}
                placeholder={placeholder}
                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')
);
 /