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.

<div id="vueapp" class="vue-app">
    <div>
        <dropdownlist 
            :data-items='items'
            :text-field="'text'"
            :filterable="true"
            @filterchange="filterChange"
        ></dropdownlist>
    </div>
</div>
import { DropDownList } from '@progress/kendo-vue-dropdowns';
import { filterBy } from '@progress/kendo-data-query';
Vue.component('dropdownlist', DropDownList);

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

new Vue({
    el: '#vueapp',
    data: function () {
        return {
            items: allData.slice()
        };
    },
    methods: {
        filterChange (event) {
            this.items = this.filterData(event.filter);
        },
        filterData(filter) {
            const data = allData.slice();
            return filterBy(data, filter);
        }
    }
});

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.

<div id="vueapp" class="vue-app">
    <div>
        <dropdownlist 
            :data-items='items'
            :text-field="'text'"
            :filterable="true"
            @filterchange="filterChange"
            :loading="loading"
        ></dropdownlist>
    </div>
</div>
import Vue from 'vue';
import { DropDownList } from '@progress/kendo-vue-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;

Vue.component('dropdownlist', DropDownList);

new Vue({
    el: '#vueapp',
    data: function () {
        return {
            items: allData.slice(),
            loading: false
        };
    },
    methods: {
        filterChange(event) {
            clearTimeout(this.timeout);
            this.timeout = setTimeout(() => {
                this.items = this.filterData(event.filter);
                this.loading = false;
            }, delay);
    
            this.loading = true;
        },
        filterData(filter) {
            const data = allData.slice();
            return filterBy(data, filter);
        }
    }
});

Minimum Filter Length

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

<div id="vueapp" class="vue-app">
    <div>
        <dropdownlist 
            :data-items='items'
            :text-field="'text'"
            :filterable="true"
            @filterchange="filterChange"
        ></dropdownlist>
    </div>
</div>
import Vue from 'vue';
import { DropDownList } from '@progress/kendo-vue-dropdowns';
import { filterBy } from '@progress/kendo-data-query';

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

Vue.component('dropdownlist', DropDownList);

new Vue({
    el: '#vueapp',
    data: function () {
        return {
            items: allData.slice()
        };
    },
    methods: {
        filterChange(event) {
            const newData = event.filter.value.length >= 3 ?
            this.filterData(event.filter) : allData.slice();

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

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.

<div id="vueapp" class="vue-app">
    <div>
        <dropdownlist
            :data-items="dataItems"
            :value="value"
            @change="onChange"
            :data-item-key="dataItemKey"
            :text-field="textField"
            :default-item="defaultItem"
            :filterable="true"
            @filterchange="onFilterChange"
            :virtual="virtual"
            @pagechange="pageChange"
        >
        </dropdownlist>
    </div>
</div>
import Vue from 'vue';
import { DropDownList } from '@progress/kendo-vue-dropdowns';

Vue.component('dropdownlist', DropDownList);
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 });
}

new Vue({
    el: '#vueapp',
    data: function () {
        return { 
            baseUrl: `https://odatasampleservices.azurewebsites.net/V4/Northwind/Northwind.svc/`,
            init: { method: 'GET', accept: 'application/json', headers: [] },
            dataCaching: [],
            pendingRequest: undefined,
            requestStarted: false,
            dataItems: [],
            skip: 0,
            tempSkip: null,
            total: 0,
            value: null,
            filter: '',
            textField: 'ContactName',
            dataItemKey: 'CustomerID',
            defaultItem: defaultItem,
            emptyItem: emptyItem,
            pageSize: 10,
            allData: [],
            subsetData: [],
            popupSettings: {
                height: '250px'
            }
         };
    },
    computed: {
        virtual: function() {
            return {
                pageSize: pageSize,
                  // @ts-ignore
                skip: this.skip,
                  // @ts-ignore
                total: this.total
            };
        }
    },
    mounted() {
        this.requestData(0, this.filter);
    },
    destroyed() {
        this.resetCach();
    },
    methods: {
        requestData(skip, filter) {
            if (this.requestStarted) {
                clearTimeout(this.pendingRequest);
                this.pendingRequest = setTimeout(() => { this.requestData(skip, filter); }, 50);
                return;
            }
            this.tempSkip = skip;
            const url = this.baseUrl +
                `Customers?$filter=contains(ContactName,'${filter}')&$skip=${skip}&$top=${pageSize}&$count=true`;

            this.requestStarted = true;

            fetch(url)
                .then((response) => {
                     return response.json();
                })
                .then(this.afterFetch);
        },
        afterFetch(json) {
            const total = json['@odata.count'];
            const items= [];
            json.value.forEach((element, index) => {
                const { CustomerID, ContactName } = element;
                const item = { [this.dataItemKey]: CustomerID, [textField]: ContactName };
                items.push(item);
                this.dataCaching[index + this.tempSkip] = item;
            });
            if (this.tempSkip === this.skip) {
                this.dataItems = items;
                this.total = total;
            }
            this.requestStarted = false;
        },
        onFilterChange(event) {
            const filter = event.filter.value;
            this.resetCach();
            this.requestData(0, filter);
            this.dataItems = loadingData;
            this.skip = 0;
            this.filter = filter;
        },
        pageChange(event) {
            const skip = event.page.skip;
            const filter = this.filter;

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

            if (makeRequest) {
                this.requestData(skip, filter);
            }
            const data = this.getCachedData(skip);
            this.dataItems = data;
            this.skip = skip;
        },
        onChange(event) {
            const value = event.value;
            if (value && value[textField] === emptyItem[textField]) {
                return;
            }
            this.value = value;
        },
        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;
        }
    }
});

In this article