Search and autocomplete
Ng-select filters items as you type and supports custom search functions, server-side typeahead, and autocomplete scenarios.
Default search
Section titled “Default search”import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';import { DataService, Person } from '../data.service';import { NgSelectComponent } from '@ng-select/ng-select';
@Component({ selector: 'ng-search-default-example', templateUrl: './search-default-example.component.html', styleUrls: ['./search-default-example.component.scss'], changeDetection: ChangeDetectionStrategy.Eager, imports: [NgSelectComponent],})export class SearchDefaultExampleComponent implements OnInit { private dataService = inject(DataService);
people: Person[] = []; peopleLoading = false;
ngOnInit() { this.loadPeople(); }
private loadPeople() { this.peopleLoading = true; this.dataService.getPeople().subscribe((x) => { this.people = x; this.peopleLoading = false; }); }}<p>By default ng-select will search using label text. You can also use <b>loading</b> input to set loading state manually if <b>[typeahead]</b> is not used.</p>
<ng-select [items]="people" bindLabel="name" [loading]="peopleLoading"> </ng-select>Search across multiple fields using [searchFn]
Section titled “Search across multiple fields using [searchFn]”import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';import { DataService, Person } from '../data.service';import { NgOptionTemplateDirective, NgSelectComponent } from '@ng-select/ng-select';
@Component({ selector: 'ng-search-custom-example', templateUrl: './search-custom-example.component.html', styleUrls: ['./search-custom-example.component.scss'], changeDetection: ChangeDetectionStrategy.Eager, imports: [NgSelectComponent, NgOptionTemplateDirective],})export class SearchCustomExampleComponent implements OnInit { private dataService = inject(DataService);
people: Person[] = []; peopleLoading = false;
ngOnInit() { this.loadPeople(); }
customSearchFn(term: string, item: Person) { term = term.toLowerCase(); return item.name.toLowerCase().indexOf(term) > -1 || item.gender.toLowerCase() === term; }
private loadPeople() { this.peopleLoading = true; this.dataService.getPeople().subscribe((x) => { this.people = x; this.peopleLoading = false; }); }}<p>Use search term and filter on custom fields. Type <b>female</b> to see only females.</p>
<ng-select [items]="people" bindLabel="name" [loading]="peopleLoading" [searchFn]="customSearchFn"> <ng-template ng-option-tmp let-item="item"> {{ item.name }} <br /> <small>{{ item.gender }}</small> </ng-template></ng-select>Custom server-side search
Section titled “Custom server-side search”import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';import { concat, Observable, of, Subject } from 'rxjs';import { DataService, Person } from '../data.service';import { catchError, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';import { FormsModule } from '@angular/forms';import { AsyncPipe, JsonPipe } from '@angular/common';import { NgSelectComponent } from '@ng-select/ng-select';
@Component({ selector: 'ng-search-autocomplete-example', templateUrl: './search-autocomplete-example.component.html', styleUrls: ['./search-autocomplete-example.component.scss'], changeDetection: ChangeDetectionStrategy.Eager, imports: [NgSelectComponent, FormsModule, AsyncPipe, JsonPipe],})export class SearchAutocompleteExampleComponent implements OnInit { private dataService = inject(DataService);
people$: Observable<Person[]>; peopleLoading = false; peopleInput$ = new Subject<string>(); selectedPersons: Person[] = <any>[{ name: 'Karyn Wright' }, { name: 'Other' }];
ngOnInit() { this.loadPeople(); }
trackByFn(item: Person) { return item.id; }
private loadPeople() { this.people$ = concat( of([]), // default items this.peopleInput$.pipe( distinctUntilChanged(), tap(() => (this.peopleLoading = true)), switchMap((term) => this.dataService.getPeople(term).pipe( catchError(() => of([])), // empty list on error tap(() => (this.peopleLoading = false)), ), ), ), ); }}<p>Use <b>typeahead</b> to subscribe to search term and load async items.</p><label>Multi select + Typeahead + Custom items (tags)</label>
<ng-select [items]="people$ | async" bindLabel="name" [addTag]="true" [multiple]="true" [hideSelected]="true" [trackByFn]="trackByFn" [minTermLength]="2" [loading]="peopleLoading" typeToSearchText="Please enter 2 or more characters" [typeahead]="peopleInput$" [(ngModel)]="selectedPersons"></ng-select><br />
<div style="margin-bottom: 100px">Selected persons: {{ selectedPersons | json }}</div>Editable search value
Section titled “Editable search value”import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';import { DataService, Person } from '../data.service';import { Observable } from 'rxjs';import { FormsModule } from '@angular/forms';import { AsyncPipe } from '@angular/common';import { NgSelectComponent } from '@ng-select/ng-select';
@Component({ selector: 'ng-app-search-editable-example', templateUrl: './search-editable-example.component.html', styleUrls: ['./search-editable-example.component.scss'], changeDetection: ChangeDetectionStrategy.Eager, imports: [NgSelectComponent, FormsModule, AsyncPipe],})export class SearchEditableExampleComponent implements OnInit { private dataService = inject(DataService);
people$: Observable<Person[]>; selectedPersonId = '5a15b13c36e7a7f00cf0d7cb';
ngOnInit() { this.people$ = this.dataService.getPeople(); }}<p class="card-text"> By default, ng-select doesn't allow edit the current value for search. You can enable it by setting <b>[editableSearchTerm]</b> input to <b>true</b>. It's useful when you want to modify part of a long search query</p>
<ng-select [items]="people$ | async" bindLabel="name" bindValue="id" [editableSearchTerm]="true" [(ngModel)]="selectedPersonId"> </ng-select>
<br />Selected: {{ selectedPersonId }}Inputs used by the examples on this page:
| Input | Type | Default | Description |
|---|---|---|---|
| [items] | Array<any> |
[] |
Items array |
| bindLabel | string |
label |
Object property to use for label. Default label |
| bindValue | string |
- |
Object property to use for selected model. By default binds to whole object. |
| [searchable] | boolean |
true |
Allow to search for value. Default true |
| [searchFn] | (term: string, item: any) => boolean |
null |
Allow to filter by custom search function |
| [typeahead] | Subject |
- |
Custom autocomplete or advanced filter. Emits on typing only; select/close/clear reset the input without emitting (use (close) / (clear) to react to those). |
| [minTermLength] | number |
0 |
Minimum term length to start a search. Should be used with typeahead |
| typeToSearchText | string |
Type to search |
Set custom text when using Typeahead |
| [editableSearchTerm] | boolean |
false |
Allow to edit search query if option selected. Default false. Works only if multiple is false. |
| [searchWhileComposing] | boolean |
true |
Whether items should be filtered while composition started |
| notFoundText | string |
No items found |
Set custom text when filter returns empty result |
| [loading] | boolean |
- |
You can set the loading state from the outside (e.g. async items loading) |
| [addTag] | boolean | ((term: string) => any | Promise<any>) |
false |
Allows to create custom options. |
| [multiple] | boolean |
false |
Allows to select multiple items. |
| [hideSelected] | boolean |
false |
Allows to hide selected items. |
| [trackByFn] | (item: any) => any |
null |
Provide custom trackBy function |
| [clearSearchOnAdd] | boolean |
true |
Clears search input when item is selected. Default true. Default false when closeOnSelect is false |
See the NgSelectComponent API reference for the complete list of inputs and outputs.