All Components

ComboBox Overview

The ComboBox is a form component that lets you choose from a list of options.

It is a richer version of the <select> element and supports data binding, filtering, templates, and the entering of custom values.

Basic Usage

The following example demonstrates the ComboBox in action.

@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
      <input id="ac" type="checkbox" [(ngModel)]="allowCustom">
      <label for="ac">Allow custom values</label>
    </div>
    <div class="example-wrapper">
    <p>Favorite sport:</p>
    <kendo-combobox [data]="listItems" [allowCustom]="allowCustom">
    </kendo-combobox>
    </div>
  `
})
class AppComponent {
    public allowCustom: boolean = true;
    public listItems: Array<string> = ["Baseball", "Basketball", "Cricket", "Field Hockey", "Football", "Table Tennis", "Tennis", "Volleyball"];
}

Configuration

The ComboBox provides configuration options for:

Set the Item Template

Use the item template to customize the content of every list item. To define an item template, nest a <template> tag with an kendoComboBoxItemTemplate directive inside a <kendo-combobox> tag.

The template context is set to the current ComboBox component. To get a reference to the current data item, use the let-dataItem directive.

@Component({
  selector: 'my-app',
  styles: ['.template { display: inline-block; background: #333; color: #fff; border-radius: 50%; width: 18px; height: 18px; text-align: center; } '],
  template: `
    <kendo-combobox
        [data]="listItems"
        [textField]="'text'"
        [valueField]="'value'"
        [value]="selectedValue"
        [valuePrimitive]="true"
    >
        <template kendoComboBoxItemTemplate let-dataItem>
            <span class="template">{{ dataItem.value }}</span> {{ dataItem.text }}
        </template>
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public selectedValue: number = 2;
}

Set the Header Template

Use the header template to customize the popup header element. To define a header template, nest a <template> tag with a kendoComboBoxHeaderTemplate directive inside a <kendo-combobox> tag.

The template context is set to the current ComboBox component.

@Component({
  selector: 'my-app',
  styles: ['h4 { font-size: 1em; font-weight: bold; padding: 0 8px; }'],
  template: `
    <kendo-combobox
        [data]="listItems"
        [textField]="'text'"
        [valueField]="'value'"
        [value]="selectedValue"
        [valuePrimitive]="true"
    >
        <template kendoComboBoxHeaderTemplate>
            <h4>T-shirt sizes</h4>
        </template>
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public selectedValue: number = 2;
}

Use the footer template to customize the popup footer element. To define a footer template, nest a <template> tag with a kendoComboBoxFooterTemplate directive inside a <kendo-combobox> tag.

The template context is set to the current ComboBox component.

@Component({
  selector: 'my-app',
  styles: ['h4 { font-size: 1em; font-weight: bold; padding: 0 8px; }'],
  template: `
    <kendo-combobox
        [data]="listItems"
        [textField]="'text'"
        [valueField]="'value'"
        [value]="selectedValue"
        [valuePrimitive]="true"
    >
        <template kendoComboBoxFooterTemplate>
            <h4>{{listItems.length}} sizes available</h4>
        </template>
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public selectedValue: number = 2;
}

Set the No-Data Template

Use the no-data template to customize the popup content when no data is present. To define a no-data template, nest a <template> tag with a kendoComboBoxNoDataTemplate directive inside a <kendo-combobox> tag.

@Component({
  selector: 'my-app',
  styles: ['.k-i-warning { font-size: 2.5em; } h4 { font-size: 1em;}'],
  template: `
    <kendo-combobox
        [data]="listItems"
    >
        <template kendoDropDownListNoDataTemplate>
            <h4><span class="k-icon k-i-warning"></span><br /><br /> No data here</h4>
        </template>
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [];
}

Data Binding

For more information on how to handle data operation processing, refer to the article on data binding.

Value Binding

The ComboBox value can be either of the primitive (string, number) or the complex (objects) type.

To set the value, apply either of the following approaches:

  • Use the value property. If the value is set through the value property, you have to hook up to the valueChange event and manually update the value of the value property.
  • Use the ngModel value binding. If the value is set by the ngModel value binding, the framework automatically will update the corresponding field from the model after the value of the component changes.

The ComboBox does not support the simultaneous usage of the value property and the ngModel value binding.

When binding the ComboBox value, the component provides options for:

Use Primitive Type Values

If the ComboBox is bound to a dataset of primitives, its value will be of the primitive type (string, number).

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox [data]="listItems" [value]="selectedItem"></kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<string> = [ "Small", "Medium", "Large" ];
    public selectedItem: string = "Medium";
}

If the ComboBox is bound to a dataset of complex objects and the valuePrimitive property is set to true, its value will also be of the primitive type (string, number).

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox
        [data]="listItems"
        [textField]="'text'"
        [valueField]="'value'"
        [valuePrimitive]="true"
        [value]="selectedItem"
    >
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public selectedItem: number = 2;
}

Use Complex Type Values

If the ComboBox is bound to a dataset of objects, its value will be of the complex type (objects).

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox
        [data]="listItems"
        [textField]="'text'"
        [valueField]="'value'"
        [value]="selectedItem"
    >
    </kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public selectedItem: { text: string, value: number } = { text: "Medium", value: 2 };
}

Work with Custom Values

For more information on how to configure the ComboBox to accept custom values, refer to the article on working with custom values

Handle Invalid Value Errors

If the value that is being provided does not match the expected type, the ComboBox will throw a JavaScript error. To fix it, you have to change the value type or to update the settings of the component.

The following table lists the valid configuration scenarios.

Value Data ValuePrimitive
primitive primitives Not set (automatically calculated as true).
object objects Not set (automatically calculated as false).
primitive objects true (manually set by the developer).

Forms Support

It is possible to use the ComboBox in template-driven or reactive forms. The component accepts values of the complex (objects) or the primitive (strings or numbers) type. To specify the value type, set the valuePrimitive property. By default, it is set to false—the value has to match the data type.

Template-Driven Forms

The template-driven forms enable you to bind the ComboBox to the model by using the ngModel directive.

The following example demonstrates how to accomplish a two-way data binding when the model field is a complex value.

@Component({
  selector: 'my-app',
  template: `
    <form #form="ngForm">
        <div class="example-config">
            The selected gender is <strong>{{ gender | json }}</strong>
        </div>
        <label>
            Select Gender:
            <kendo-combobox
                name="gender"
                [data]="genders"
                [textField]="'text'"
                [valueField]="'value'"
                [(ngModel)]="gender"
            >
            </kendo-combobox>
        </label>
    </form>
  `
})
class AppComponent {
    public genders: Array<{ text: string, value: number }> = [
        { text: "Male", value: 1 },
        { text: "Female", value: 2 },
        { text: "Other", value: 3 }
    ];

    public gender: { text: string, value: number } = { text: "Female", value: 2 };
}

The following example demonstrates how to accomplish a two-way data binding when the model field is a primitive value.

@Component({
  selector: 'my-app',
  template: `
    <form #form="ngForm">
        <div class="example-config">
            The selected gender is <strong>{{ gender | json }}</strong>
        </div>
        <label>
            Select Gender:
            <kendo-combobox
                name="gender"
                [data]="genders"
                [textField]="'text'"
                [valueField]="'value'"
                [valuePrimitive]="true"
                [(ngModel)]="gender"
            >
            </kendo-combobox>
        </label>
    </form>
  `
})
class AppComponent {
    public genders: Array<{ text: string, value: number }> = [
        { text: "Male", value: 1 },
        { text: "Female", value: 2 },
        { text: "Other", value: 3 }
    ];

    public gender: { text: string, value: number } = 2;
}

Reactive Forms

The FormGroup provides a way to render reactive forms. For more details, refer to the Angular Documentation.

The following example demonstrates how to use the ComboBox in a reactive form with a primitive value binding.

import {
    FormsModule,
    ReactiveFormsModule,
    FormGroup,
    FormControl
} from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]="myForm">
        <div class="example-config">
            <p>The form is valid: <strong>{{myForm.controls.gender.valid}}</strong></p>
            <p>The form.gender value is: <strong>{{myForm.controls.gender.value}}</strong></p>
        </div>
        <label>
            Select gender
            <kendo-combobox
                formControlName="gender"
                [data]="genders"
                [textField]="'text'"
                [valueField]="'value'"
                [valuePrimitive]="true"
                required
            >
            </kendo-combobox>
        </label>
    </form>
  `
})
class AppComponent {
    public genders: Array<{ text: string, value: number }> = [
        { text: "Male", value: 1 },
        { text: "Female", value: 2 },
        { text: "Other", value: 3 }
    ];

    public myForm: FormGroup = new FormGroup({
        gender: new FormControl(2)
    });
}

The following example demonstrates how to use the ComboBox in a reactive form with a complex value binding.

import {
    FormsModule,
    ReactiveFormsModule,
    FormGroup,
    FormControl
} from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]="myForm">
        <div class="example-config">
            <p>The form is valid: <strong>{{myForm.controls.gender.valid}}</strong></p>
            <p>The form.gender value is: <strong>{{myForm.controls.gender.value | json}}</strong></p>
        </div>
        <label>
            Select gender
            <kendo-combobox
                formControlName="gender"
                [data]="genders"
                [textField]="'text'"
                [valueField]="'value'"
                required
            >
            </kendo-combobox>
        </label>
    </form>
  `
})
class AppComponent {
    public genders: Array<{ text: string, value: number }> = [
        { text: "Male", value: 1 },
        { text: "Female", value: 2 },
        { text: "Other", value: 3 }
    ];

    public myForm: FormGroup = new FormGroup({
        gender: new FormControl({ text: "Female", value: 2 })
    });
}

Filtering

To enable the filtering functionality, set the filterable property to true. Whenever the user modifies the input value, the ComboBox triggers a filterChange event. The event argument contains the typed string value that you can use to filter the source.

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox
        [data]="data"
        [textField]="'text'"
        [valueField]="'value'"
        [filterable]="true"
        (filterChange)="handleFilter($event)"
        [placeholder]="'T-shirt size'"
    >
    </kendo-combobox>
  `
})
class AppComponent {
    public source: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public data: Array<{ text: string, value: number }>;

    constructor() {
        this.data = this.source.slice();
    }

    handleFilter(value) {
        this.data = this.source.filter((s) => s.text.toLowerCase().indexOf(value.toLowerCase()) !== -1);
    }
}

To filter the data after a delay, use a similar implementation.

import { Component, ViewChild } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs/Rx';

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox
        #list
        [data]="data"
        [filterable]="true"
        [textField]="'text'"
        [valueField]="'value'"
    >
    </kendo-combobox>
  `
})
export class AppComponent {
    @ViewChild("list") list;

    public source: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public data: Array<{ text: string, value: number }>;

    constructor() {
        this.data = this.source.slice();
    }

    ngAfterViewInit() {
      const contains = value => s => s.text.toLowerCase().indexOf(value.toLowerCase()) !== -1);
      
      this.list.filterChange.asObservable().switchMap(value => Observable.from([this.source])
        .delay(1000)
        .map((data) =>  data.filter(contains(value))))
        .subscribe(x => this.data = x);
    }

}

Suggestions

To turn on suggestions set suggest property to true. Whenever the user modifies the input value, the ComboBox will autocomplete the user input with the first text match. If the first text match does not begin with the current user input, no suggestion will be displayed.

@Component({
  selector: 'my-app',
  template: `
    <kendo-combobox [data]="listItems" [suggest]="true" [placeholder]="'e.g. Austria'"></kendo-combobox>
  `
})
class AppComponent {
    public listItems: Array<string> = [
     "Albania",
     "Andorra",
     "Armenia",:
     "Austria",
     "Azerbaijan",
     "Belarus",
     "Belgium",
     "Bosnia & Herzegovina",
     "Bulgaria",
     "Croatia",
     "Cyprus",
     "Czech Republic",
     "Denmark",
     "Estonia",
     "Finland",
     "France",
     "Georgia",
     "Germany",
     "Greece"
     ];
}

Cascading ComboBoxes

For more information on how to filter a series of ComboBoxes based on the selected option in each of the previous ones, refer to the article on cascading ComboBoxes.

Keyboard Navigation

For more information on the keyboard shortcuts the ComboBox supports, refer to the article on keyboard navigation.

Accessibility

For more information on the accessibility features of the ComboBox, refer to the article on accessibility.

Events

On Changing the Item Selection

The selectionChange event is triggered when the item selection is changed.

@Component({
  selector: 'my-app',
  template: `
    <div class="example-wrapper">
        <p>T-shirt size:</p>
        <kendo-combobox
            [data]="data"
            [textField]="'text'"
            [valueField]="'value'"
            (selectionChange)="handleSelection($event)"
        >
        </kendo-combobox>
    </div>
    <div class="example-config">
        <h4>Last 10 calls:</h4>
        <p *ngFor="let call of eventCalls">{{ call.name }}: <strong>{{ call.value | json }}</strong></p>
    </div>
  `
})
class AppComponent {
    public data: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public eventCalls: Array<any> = [];

    last10Calls() {
        const end = this.eventCalls.length;

        return this.eventCalls.slice(Math.max(0, end - 10), end);
    }

    handleSelection(value) {
        this.eventCalls = this.last10Calls().concat([ { name: 'select', value: value } ]);
    }
}

On Changing the Value

The valueChange event is triggered when the selected value is changed. If the popup is open, the valueChange event will not fire. To raise the change event when the popup is still opened, either blur the component or press ENTER.

@Component({
  selector: 'my-app',
  template: `
    <div class="example-wrapper">
        <p>T-shirt size:</p>
        <kendo-combobox
            [data]="data"
            [textField]="'text'"
            [valueField]="'value'"
            (valueChange)="handleValue($event)"
        >
        </kendo-combobox>
    </div>
    <div class="example-config">
        <h4>Last 10 calls:</h4>
        <p *ngFor="let call of eventCalls">{{ call.name }}: <strong>{{ call.value | json }}</strong></p>
    </div>
  `
})
class AppComponent {
    public data: Array<{ text: string, value: number }> = [
        { text: "Small", value: 1 },
        { text: "Medium", value: 2 },
        { text: "Large", value: 3 }
    ];

    public eventCalls: Array<any> = [];

    last10Calls() {
        const end = this.eventCalls.length;

        return this.eventCalls.slice(Math.max(0, end - 10), end);
    }

    handleValue(value) {
        this.eventCalls = this.last10Calls().concat([ { name: 'change', value: value } ]);
    }
}

On Changing the Filter

The filterChange event fires when the user types inside the filter input. For more details, refer to the section on filtering.

In this article