The easiest way to add the typeahead component to your app (will be added to the root module)
Basic array
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-basic', templateUrl: './basic.html', standalone: false }) export class DemoTypeaheadBasicComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
With animation
You can enable animation via isAnimated
input or config option
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [isAnimated]="true" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-animated', templateUrl: './animated.html', standalone: false }) export class DemoTypeaheadAnimatedComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Adaptive position
You can enable adaptive position via adaptivePosition
input or config option
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [adaptivePosition]="true" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-adaptive-position', templateUrl: './adaptive-position.html', standalone: false }) export class DemoTypeaheadAdaptivePositionComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Item template
Model:
<ng-template #customItemTemplate let-model="item" let-index="index"> <h5>This is: {{model | json}} Index: {{ index }}</h5> </ng-template> <pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadItemTemplate]="customItemTemplate" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-item-template', templateUrl: './item-template.html', standalone: false }) export class DemoTypeaheadItemTemplateComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
List template
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [optionsListTemplate]="customListTemplate" class="form-control"> <ng-template #customListTemplate let-matches="matches" let-query="query" let-typeaheadTemplateMethods> <ul class="custom-list-group"> <li class="custom-list-group-item" *ngFor="let match of matches" [class.active]="typeaheadTemplateMethods.isActive(match)" (click)="typeaheadTemplateMethods.selectMatch(match, $event)" (mouseenter)="typeaheadTemplateMethods.selectActive(match)"> {{ match.item }} </li> </ul> </ng-template>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-templates', templateUrl: './list-template.html', styles: [` .custom-list-group { display: flex; flex-direction: column; width: 300px; padding-left: 0; margin: 0; list-style: none; } .custom-list-group-item { position: relative; display: block; padding: .75rem 1.25rem; background-color: #fff; } .custom-list-group-item.active { z-index: 2; color: #fff; background-color: #FF4461; border-color: #FF4461; } `], standalone: false }) export class DemoTypeaheadListTemplateComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Option field
Model:
<pre class="card card-block card-header mb-3">Model: {{customSelected | json}}</pre> <input [(ngModel)]="customSelected" [typeahead]="statesComplex" typeaheadOptionField="name" class="form-control">
import { Component } from '@angular/core'; import { DataSourceType } from '../interfaces/typeahead.interfaces'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-field', templateUrl: './field.html', standalone: false }) export class DemoTypeaheadFieldComponent { customSelected?: string; statesComplex: DataSourceType[] = [ { id: 1, name: 'Alabama', region: 'South' }, { id: 2, name: 'Alaska', region: 'West' }, { id: 3, name: 'Arizona', region: 'West' }, { id: 4, name: 'Arkansas', region: 'South' }, { id: 5, name: 'California', region: 'West' }, { id: 6, name: 'Colorado', region: 'West' }, { id: 7, name: 'Connecticut', region: 'Northeast' }, { id: 8, name: 'Delaware', region: 'South' }, { id: 9, name: 'Florida', region: 'South' }, { id: 10, name: 'Georgia', region: 'South' }, { id: 11, name: 'Hawaii', region: 'West' }, { id: 12, name: 'Idaho', region: 'West' }, { id: 13, name: 'Illinois', region: 'Midwest' }, { id: 14, name: 'Indiana', region: 'Midwest' }, { id: 15, name: 'Iowa', region: 'Midwest' }, { id: 16, name: 'Kansas', region: 'Midwest' }, { id: 17, name: 'Kentucky', region: 'South' }, { id: 18, name: 'Louisiana', region: 'South' }, { id: 19, name: 'Maine', region: 'Northeast' }, { id: 21, name: 'Maryland', region: 'South' }, { id: 22, name: 'Massachusetts', region: 'Northeast' }, { id: 23, name: 'Michigan', region: 'Midwest' }, { id: 24, name: 'Minnesota', region: 'Midwest' }, { id: 25, name: 'Mississippi', region: 'South' }, { id: 26, name: 'Missouri', region: 'Midwest' }, { id: 27, name: 'Montana', region: 'West' }, { id: 28, name: 'Nebraska', region: 'Midwest' }, { id: 29, name: 'Nevada', region: 'West' }, { id: 30, name: 'New Hampshire', region: 'Northeast' }, { id: 31, name: 'New Jersey', region: 'Northeast' }, { id: 32, name: 'New Mexico', region: 'West' }, { id: 33, name: 'New York', region: 'Northeast' }, { id: 34, name: 'North Dakota', region: 'Midwest' }, { id: 35, name: 'North Carolina', region: 'South' }, { id: 36, name: 'Ohio', region: 'Midwest' }, { id: 37, name: 'Oklahoma', region: 'South' }, { id: 38, name: 'Oregon', region: 'West' }, { id: 39, name: 'Pennsylvania', region: 'Northeast' }, { id: 40, name: 'Rhode Island', region: 'Northeast' }, { id: 41, name: 'South Carolina', region: 'South' }, { id: 42, name: 'South Dakota', region: 'Midwest' }, { id: 43, name: 'Tennessee', region: 'South' }, { id: 44, name: 'Texas', region: 'South' }, { id: 45, name: 'Utah', region: 'West' }, { id: 46, name: 'Vermont', region: 'Northeast' }, { id: 47, name: 'Virginia', region: 'South' }, { id: 48, name: 'Washington', region: 'South' }, { id: 49, name: 'West Virginia', region: 'South' }, { id: 50, name: 'Wisconsin', region: 'Midwest' }, { id: 51, name: 'Wyoming', region: 'West' } ]; }
Async data
Model:
<pre class="card card-block card-header">Model: {{ asyncSelected | json }}</pre> <input [(ngModel)]="asyncSelected" [typeahead]="dataSource" [typeaheadAsync]="true" typeaheadOptionField="name" (typeaheadLoading)="changeTypeaheadLoading($event)" placeholder="Locations loaded via observable" class="form-control">
import { Component } from '@angular/core'; import { Observable, of, Subscriber } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; import { DataSourceType } from '../interfaces/typeahead.interfaces'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-async', templateUrl: './async.html', standalone: false }) export class DemoTypeaheadAsyncComponent { asyncSelected?: string; dataSource: Observable<DataSourceType[]>; typeaheadLoading?: boolean; statesComplex: DataSourceType[] = [ { id: 1, name: 'Alabama', region: 'South' }, { id: 2, name: 'Alaska', region: 'West' }, { id: 3, name: 'Arizona', region: 'West' }, { id: 4, name: 'Arkansas', region: 'South' }, { id: 5, name: 'California', region: 'West' }, { id: 6, name: 'Colorado', region: 'West' }, { id: 7, name: 'Connecticut', region: 'Northeast' }, { id: 8, name: 'Delaware', region: 'South' }, { id: 9, name: 'Florida', region: 'South' }, { id: 10, name: 'Georgia', region: 'South' }, { id: 11, name: 'Hawaii', region: 'West' }, { id: 12, name: 'Idaho', region: 'West' }, { id: 13, name: 'Illinois', region: 'Midwest' }, { id: 14, name: 'Indiana', region: 'Midwest' }, { id: 15, name: 'Iowa', region: 'Midwest' }, { id: 16, name: 'Kansas', region: 'Midwest' }, { id: 17, name: 'Kentucky', region: 'South' }, { id: 18, name: 'Louisiana', region: 'South' }, { id: 19, name: 'Maine', region: 'Northeast' }, { id: 21, name: 'Maryland', region: 'South' }, { id: 22, name: 'Massachusetts', region: 'Northeast' }, { id: 23, name: 'Michigan', region: 'Midwest' }, { id: 24, name: 'Minnesota', region: 'Midwest' }, { id: 25, name: 'Mississippi', region: 'South' }, { id: 26, name: 'Missouri', region: 'Midwest' }, { id: 27, name: 'Montana', region: 'West' }, { id: 28, name: 'Nebraska', region: 'Midwest' }, { id: 29, name: 'Nevada', region: 'West' }, { id: 30, name: 'New Hampshire', region: 'Northeast' }, { id: 31, name: 'New Jersey', region: 'Northeast' }, { id: 32, name: 'New Mexico', region: 'West' }, { id: 33, name: 'New York', region: 'Northeast' }, { id: 34, name: 'North Dakota', region: 'Midwest' }, { id: 35, name: 'North Carolina', region: 'South' }, { id: 36, name: 'Ohio', region: 'Midwest' }, { id: 37, name: 'Oklahoma', region: 'South' }, { id: 38, name: 'Oregon', region: 'West' }, { id: 39, name: 'Pennsylvania', region: 'Northeast' }, { id: 40, name: 'Rhode Island', region: 'Northeast' }, { id: 41, name: 'South Carolina', region: 'South' }, { id: 42, name: 'South Dakota', region: 'Midwest' }, { id: 43, name: 'Tennessee', region: 'South' }, { id: 44, name: 'Texas', region: 'South' }, { id: 45, name: 'Utah', region: 'West' }, { id: 46, name: 'Vermont', region: 'Northeast' }, { id: 47, name: 'Virginia', region: 'South' }, { id: 48, name: 'Washington', region: 'South' }, { id: 49, name: 'West Virginia', region: 'South' }, { id: 50, name: 'Wisconsin', region: 'Midwest' }, { id: 51, name: 'Wyoming', region: 'West' } ]; constructor() { this.dataSource = new Observable((observer: Subscriber<string>) => { // Runs on every search observer.next(this.asyncSelected); }) .pipe( mergeMap((token: string) => this.getStatesAsObservable(token)) ); } getStatesAsObservable(token: string): Observable<DataSourceType[]> { const query = new RegExp(token, 'i'); return of( this.statesComplex.filter((state: DataSourceType) => { return query.test(state.name); }) ); } changeTypeaheadLoading(e: boolean): void { this.typeaheadLoading = e; } }
Async using http request
Use http request to search for data. If you need to handle http error, do this inside tap
operator.
Enter search value several times (10-15), and after a few success responses API should return an error
(GitHub limit for requests)
Model:
<pre class="card card-block card-header">Model: {{ search | json }}</pre> <input [(ngModel)]="search" typeaheadOptionField="login" [typeahead]="suggestions$" [typeaheadAsync]="true" class="form-control" placeholder="Enter GitHub username"> <div class="alert alert-danger" role="alert" *ngIf="errorMessage"> {{ errorMessage }} </div>
import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { noop, Observable, Observer, of } from 'rxjs'; import { map, switchMap, tap } from 'rxjs/operators'; interface GitHubUserSearchResponse { total_count: number; incomplete_results: boolean; items: GitHubUser[]; } interface GitHubUser { login: string; id: number; node_id: string; avatar_url: string; gravatar_id: string; url: string; html_url: string; followers_url: string; subscriptions_url: string; organizations_url: string; repos_url: string; received_events_url: string; type: string; score: number; } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-async-http', templateUrl: './async-http-request.html', standalone: false }) export class DemoTypeaheadAsyncHttpRequestComponent implements OnInit { search?: string; suggestions$?: Observable<GitHubUser[]>; errorMessage?: string; constructor(private http: HttpClient) {} ngOnInit(): void { this.suggestions$ = new Observable((observer: Observer<string | undefined>) => { observer.next(this.search); }).pipe( switchMap((query: string) => { if (query) { // using github public api to get users by name return this.http.get<GitHubUserSearchResponse>( 'https://api.github.com/search/users', { params: { q: query } }).pipe( map((data: GitHubUserSearchResponse) => data && data.items || []), tap(() => noop, err => { // in case of http error this.errorMessage = err && err.message || 'Something goes wrong'; }) ); } return of([]); }) ); } }
Cancel on focus lost
Set config property cancelRequestOnFocusLost
to true
if you want to cancel async request on focus lost event
Model:
<pre class="card card-block card-header">Model: {{asyncSelected | json}}</pre> <input [(ngModel)]="asyncSelected" [typeahead]="dataSource" (typeaheadLoading)="changeTypeaheadLoading($event)" (typeaheadOnSelect)="typeaheadOnSelect($event)" [typeaheadOptionsLimit]="7" typeaheadOptionField="name" placeholder="Locations loaded with timeout" class="form-control"> <div *ngIf="typeaheadLoading">Loading</div>
import { Component } from '@angular/core'; import { Observable, Observer, of } from 'rxjs'; import { TypeaheadMatch } from 'ngx-bootstrap/typeahead'; import { mergeMap, delay } from 'rxjs/operators'; import { TypeaheadConfig } from 'ngx-bootstrap/typeahead'; import { DataSourceType } from '../interfaces/typeahead.interfaces'; export function getTypeaheadConfig(): TypeaheadConfig { return Object.assign(new TypeaheadConfig(), { cancelRequestOnFocusLost: true }); } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-cancel-on-focus-lost', templateUrl: './cancel-on-focus-lost.html', providers: [{ provide: TypeaheadConfig, useFactory: getTypeaheadConfig }], standalone: false }) export class DemoTypeaheadCancelRequestOnFocusLostComponent { asyncSelected?: string; typeaheadLoading?: boolean; dataSource: Observable<DataSourceType[]>; statesComplex: DataSourceType[] = [ { id: 1, name: 'Alabama', region: 'South' }, { id: 2, name: 'Alaska', region: 'West' }, { id: 3, name: 'Arizona', region: 'West' }, { id: 4, name: 'Arkansas', region: 'South' }, { id: 5, name: 'California', region: 'West' }, { id: 6, name: 'Colorado', region: 'West' }, { id: 7, name: 'Connecticut', region: 'Northeast' }, { id: 8, name: 'Delaware', region: 'South' }, { id: 9, name: 'Florida', region: 'South' }, { id: 10, name: 'Georgia', region: 'South' }, { id: 11, name: 'Hawaii', region: 'West' }, { id: 12, name: 'Idaho', region: 'West' }, { id: 13, name: 'Illinois', region: 'Midwest' }, { id: 14, name: 'Indiana', region: 'Midwest' }, { id: 15, name: 'Iowa', region: 'Midwest' }, { id: 16, name: 'Kansas', region: 'Midwest' }, { id: 17, name: 'Kentucky', region: 'South' }, { id: 18, name: 'Louisiana', region: 'South' }, { id: 19, name: 'Maine', region: 'Northeast' }, { id: 21, name: 'Maryland', region: 'South' }, { id: 22, name: 'Massachusetts', region: 'Northeast' }, { id: 23, name: 'Michigan', region: 'Midwest' }, { id: 24, name: 'Minnesota', region: 'Midwest' }, { id: 25, name: 'Mississippi', region: 'South' }, { id: 26, name: 'Missouri', region: 'Midwest' }, { id: 27, name: 'Montana', region: 'West' }, { id: 28, name: 'Nebraska', region: 'Midwest' }, { id: 29, name: 'Nevada', region: 'West' }, { id: 30, name: 'New Hampshire', region: 'Northeast' }, { id: 31, name: 'New Jersey', region: 'Northeast' }, { id: 32, name: 'New Mexico', region: 'West' }, { id: 33, name: 'New York', region: 'Northeast' }, { id: 34, name: 'North Dakota', region: 'Midwest' }, { id: 35, name: 'North Carolina', region: 'South' }, { id: 36, name: 'Ohio', region: 'Midwest' }, { id: 37, name: 'Oklahoma', region: 'South' }, { id: 38, name: 'Oregon', region: 'West' }, { id: 39, name: 'Pennsylvania', region: 'Northeast' }, { id: 40, name: 'Rhode Island', region: 'Northeast' }, { id: 41, name: 'South Carolina', region: 'South' }, { id: 42, name: 'South Dakota', region: 'Midwest' }, { id: 43, name: 'Tennessee', region: 'South' }, { id: 44, name: 'Texas', region: 'South' }, { id: 45, name: 'Utah', region: 'West' }, { id: 46, name: 'Vermont', region: 'Northeast' }, { id: 47, name: 'Virginia', region: 'South' }, { id: 48, name: 'Washington', region: 'South' }, { id: 49, name: 'West Virginia', region: 'South' }, { id: 50, name: 'Wisconsin', region: 'Midwest' }, { id: 51, name: 'Wyoming', region: 'West' } ]; constructor() { this.dataSource = new Observable((observer: Observer<string | undefined>) => { // Runs on every search observer.next(this.asyncSelected); }).pipe( mergeMap((token: string) => this.getStatesAsObservable(token)), delay(1000) ); } getStatesAsObservable(token: string): Observable<DataSourceType[]> { const query = new RegExp(token, 'i'); return of( this.statesComplex.filter((state: DataSourceType) => { return query.test(state.name); }) ); } changeTypeaheadLoading(e: boolean): void { this.typeaheadLoading = e; } typeaheadOnSelect(e: TypeaheadMatch): void { console.log('Selected value: ', e.value); } }
With delay
Use typeaheadWaitMs
to set minimal waiting time after last character typed
before typeahead kicks-in. In example a search begins with delay in 1 second
Model:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadWaitMs]="1000" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-delay', templateUrl: './delay.html', standalone: false }) export class DemoTypeaheadDelayComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Template-driven forms
Typeahead can be used in template-driven forms. Keep in mind that value of ngModel
is
string
Model: { "address": "312 Sundown Lane", "state": null }
<pre class="card card-block card-header">Model: {{model | json}}</pre> <form> <div class="form-group mb-3"> <label for="address">Address</label> <input type="text" class="form-control" id="address" required [(ngModel)]="model.address" name="address"> </div> <div class="form-group mb-3"> <label for="state">State</label> <input id="state" class="form-control" name="state" [(ngModel)]="model.state" [typeahead]="states"> </div> </form>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-form', templateUrl: './form.html', standalone: false }) export class DemoTypeaheadFormComponent { model = { address: '312 Sundown Lane', state: null }; states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Reactive forms
Typeahead can be used in reactive forms
Model: null
<pre class="card card-block card-header">Model: {{myForm.value.state | json}}</pre> <form [formGroup]="myForm"> <input formControlName="state" [typeahead]="states" [typeaheadOptionsLimit]="7" [typeaheadMinLength]="0" placeholder="Typeahead inside a form" class="form-control"> </form>
import { Component } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-reactive-form', templateUrl: './reactive-form.html', standalone: false }) export class DemoTypeaheadReactiveFormComponent { stateCtrl = new UntypedFormControl(); myForm = new UntypedFormGroup({ state: this.stateCtrl }); states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Grouping results
Model:
<pre class="card card-block card-header mb-3">Model: {{groupSelected | json}}</pre> <input [(ngModel)]="groupSelected" [typeahead]="statesComplex" typeaheadOptionField="name" typeaheadGroupField="region" class="form-control">
import { Component } from '@angular/core'; import { DataSourceType } from '../interfaces/typeahead.interfaces'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-grouping', templateUrl: './grouping.html', standalone: false }) export class DemoTypeaheadGroupingComponent { groupSelected?: string; statesComplex: DataSourceType[] = [ { id: 1, name: 'Alabama', region: 'South' }, { id: 2, name: 'Alaska', region: 'West' }, { id: 3, name: 'Arizona', region: 'West' }, { id: 4, name: 'Arkansas', region: 'South' }, { id: 5, name: 'California', region: 'West' }, { id: 6, name: 'Colorado', region: 'West' }, { id: 7, name: 'Connecticut', region: 'Northeast' }, { id: 8, name: 'Delaware', region: 'South' }, { id: 9, name: 'Florida', region: 'South' }, { id: 10, name: 'Georgia', region: 'South' }, { id: 11, name: 'Hawaii', region: 'West' }, { id: 12, name: 'Idaho', region: 'West' }, { id: 13, name: 'Illinois', region: 'Midwest' }, { id: 14, name: 'Indiana', region: 'Midwest' }, { id: 15, name: 'Iowa', region: 'Midwest' }, { id: 16, name: 'Kansas', region: 'Midwest' }, { id: 17, name: 'Kentucky', region: 'South' }, { id: 18, name: 'Louisiana', region: 'South' }, { id: 19, name: 'Maine', region: 'Northeast' }, { id: 21, name: 'Maryland', region: 'South' }, { id: 22, name: 'Massachusetts', region: 'Northeast' }, { id: 23, name: 'Michigan', region: 'Midwest' }, { id: 24, name: 'Minnesota', region: 'Midwest' }, { id: 25, name: 'Mississippi', region: 'South' }, { id: 26, name: 'Missouri', region: 'Midwest' }, { id: 27, name: 'Montana', region: 'West' }, { id: 28, name: 'Nebraska', region: 'Midwest' }, { id: 29, name: 'Nevada', region: 'West' }, { id: 30, name: 'New Hampshire', region: 'Northeast' }, { id: 31, name: 'New Jersey', region: 'Northeast' }, { id: 32, name: 'New Mexico', region: 'West' }, { id: 33, name: 'New York', region: 'Northeast' }, { id: 34, name: 'North Dakota', region: 'Midwest' }, { id: 35, name: 'North Carolina', region: 'South' }, { id: 36, name: 'Ohio', region: 'Midwest' }, { id: 37, name: 'Oklahoma', region: 'South' }, { id: 38, name: 'Oregon', region: 'West' }, { id: 39, name: 'Pennsylvania', region: 'Northeast' }, { id: 40, name: 'Rhode Island', region: 'Northeast' }, { id: 41, name: 'South Carolina', region: 'South' }, { id: 42, name: 'South Dakota', region: 'Midwest' }, { id: 43, name: 'Tennessee', region: 'South' }, { id: 44, name: 'Texas', region: 'South' }, { id: 45, name: 'Utah', region: 'West' }, { id: 46, name: 'Vermont', region: 'Northeast' }, { id: 47, name: 'Virginia', region: 'South' }, { id: 48, name: 'Washington', region: 'South' }, { id: 49, name: 'West Virginia', region: 'South' }, { id: 50, name: 'Wisconsin', region: 'Midwest' }, { id: 51, name: 'Wyoming', region: 'West' } ]; }
Ignore spaces and order
After setting typeaheadSingleWords
input property to true
order of typed symbols and spaces between them will be ignored. For example, "zona ari"
will match with "Arizona"
typeaheadSingleWords: true Model:
<button type="button" class="btn btn-primary" (click)="typeaheadSingleWords = !typeaheadSingleWords">Toggle typeaheadSingleWords </button> <pre class="card card-block card-header"> typeaheadSingleWords: {{typeaheadSingleWords}} Model: {{selected | json}} </pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadSingleWords]="typeaheadSingleWords" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-single-world', templateUrl: './single-world.html', standalone: false }) export class DemoTypeaheadSingleWorldComponent { typeaheadSingleWords = true; selected?: string; states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Phrase delimiters
Set the word delimiter by typeaheadPhraseDelimiters
to match exact phrase.
This is demo with delimeters "&
" and ",
"
Model:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadSingleWords]="true" typeaheadPhraseDelimiters="&," class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-phrase-delimiters', templateUrl: './phrase-delimiters.html', standalone: false }) export class DemoTypeaheadPhraseDelimitersComponent { selected?: string; states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Dropup
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [dropup]="true" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-dropup', templateUrl: './dropup.html', standalone: false }) export class DemoTypeaheadDropupComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
On blur
Returns an option on which user lost a focus. To reproduce start typing the name of the state, then focus on one of the options with mouse or arrow keys and click outside of the typeahead
Model:
Option on blur:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <pre class="card card-block card-header">Option on blur: {{optionOnBlur | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" (typeaheadOnBlur)="typeaheadOnBlur($event)" class="form-control">
import { Component } from '@angular/core'; import { TypeaheadMatch, TypeaheadConfig } from 'ngx-bootstrap/typeahead'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-on-blur', templateUrl: './on-blur.html', providers: [{ provide: TypeaheadConfig, useValue: { selectItemOnBlur: true, hideResultsOnBlur: true } }], standalone: false }) export class DemoTypeaheadOnBlurComponent { selected?: string; optionOnBlur?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; typeaheadOnBlur(event?: TypeaheadMatch<string>): void { this.optionOnBlur = event?.item; } }
Append to body
container
is an input property specifying the element the typeahead should be appended to.
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" container="body" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-container', templateUrl: './container.html', standalone: false }) export class DemoTypeaheadContainerComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
No result
Used to display the state when no matches were found. To see message "No Results Found" enter the value that doesn't match anything from the list
Model:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <div class="alert alert-danger" *ngIf="noResult">No Results Found</div> <input [(ngModel)]="selected" [typeahead]="states" (typeaheadNoResults)="typeaheadNoResults($event)" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-no-result', templateUrl: './no-result.html', standalone: false }) export class DemoTypeaheadNoResultComponent { selected?: string; noResult = false; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; typeaheadNoResults(event: boolean): void { this.noResult = event; } }
Scrollable
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="5" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-scrollable', templateUrl: './scrollable.html', standalone: false }) export class DemoTypeaheadScrollableComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Latinize
Use typeaheadLatinize
property for matching latin symbols. If it is set
to true
the word súper would match super and vice versa.
Model:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="frenchWords" [typeaheadLatinize]="true" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-latinize', templateUrl: './latinize.html', standalone: false }) export class DemoTypeaheadLatinizeComponent { selected?: string; frenchWords: string[] = [ 'popularisé', 'français', 'intéressé', 'générateur', 'répandue', 'répétition', 'súper' ]; }
On select / On preview
typeaheadOnSelect
event is fired when an option was selected.
Returns an object with this option.
typeaheadOnPreview
event is fired when an option was highlighted.
Returns an object with this option.
Model:
Selected option:
<pre class="card card-block card-header mb-3">Model: {{selectedValue | json}}</pre> <pre class="card card-block card-header mb-3">Selected option: {{selectedOption | json}}</pre> <div> <input [(ngModel)]="selectedValue" [typeahead]="states" typeaheadOptionField="name" (typeaheadOnSelect)="onSelect($event)" (typeaheadOnPreview)="onPreview($event)" class="form-control"> <div style="float:right;width:160px;" class="card card-block card-header mb-3"> Preview region: <span *ngIf="previewOption; else noPreviewOption">{{previewOption?.region}}</span> <ng-template #noPreviewOption><span>N/A</span></ng-template> </div> </div>
import { Component } from '@angular/core'; import { TypeaheadMatch } from 'ngx-bootstrap/typeahead'; import { DataSourceType } from '../interfaces/typeahead.interfaces'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-on-select', templateUrl: './on-select.html', standalone: false }) export class DemoTypeaheadOnSelectComponent { selectedValue?: string; selectedOption?: DataSourceType; previewOption?: DataSourceType; states: DataSourceType[] = [ { id: 1, name: 'Alabama', region: 'South' }, { id: 2, name: 'Alaska', region: 'West' }, { id: 3, name: 'Arizona', region: 'West' }, { id: 4, name: 'Arkansas', region: 'South' }, { id: 5, name: 'California', region: 'West' }, { id: 6, name: 'Colorado', region: 'West' }, { id: 7, name: 'Connecticut', region: 'Northeast' }, { id: 8, name: 'Delaware', region: 'South' }, { id: 9, name: 'Florida', region: 'South' }, { id: 10, name: 'Georgia', region: 'South' }, { id: 11, name: 'Hawaii', region: 'West' }, { id: 12, name: 'Idaho', region: 'West' }, { id: 13, name: 'Illinois', region: 'Midwest' }, { id: 14, name: 'Indiana', region: 'Midwest' }, { id: 15, name: 'Iowa', region: 'Midwest' }, { id: 16, name: 'Kansas', region: 'Midwest' }, { id: 17, name: 'Kentucky', region: 'South' }, { id: 18, name: 'Louisiana', region: 'South' }, { id: 19, name: 'Maine', region: 'Northeast' }, { id: 21, name: 'Maryland', region: 'South' }, { id: 22, name: 'Massachusetts', region: 'Northeast' }, { id: 23, name: 'Michigan', region: 'Midwest' }, { id: 24, name: 'Minnesota', region: 'Midwest' }, { id: 25, name: 'Mississippi', region: 'South' }, { id: 26, name: 'Missouri', region: 'Midwest' }, { id: 27, name: 'Montana', region: 'West' }, { id: 28, name: 'Nebraska', region: 'Midwest' }, { id: 29, name: 'Nevada', region: 'West' }, { id: 30, name: 'New Hampshire', region: 'Northeast' }, { id: 31, name: 'New Jersey', region: 'Northeast' }, { id: 32, name: 'New Mexico', region: 'West' }, { id: 33, name: 'New York', region: 'Northeast' }, { id: 34, name: 'North Dakota', region: 'Midwest' }, { id: 35, name: 'North Carolina', region: 'South' }, { id: 36, name: 'Ohio', region: 'Midwest' }, { id: 37, name: 'Oklahoma', region: 'South' }, { id: 38, name: 'Oregon', region: 'West' }, { id: 39, name: 'Pennsylvania', region: 'Northeast' }, { id: 40, name: 'Rhode Island', region: 'Northeast' }, { id: 41, name: 'South Carolina', region: 'South' }, { id: 42, name: 'South Dakota', region: 'Midwest' }, { id: 43, name: 'Tennessee', region: 'South' }, { id: 44, name: 'Texas', region: 'South' }, { id: 45, name: 'Utah', region: 'West' }, { id: 46, name: 'Vermont', region: 'Northeast' }, { id: 47, name: 'Virginia', region: 'South' }, { id: 48, name: 'Washington', region: 'South' }, { id: 49, name: 'West Virginia', region: 'South' }, { id: 50, name: 'Wisconsin', region: 'Midwest' }, { id: 51, name: 'Wyoming', region: 'West' } ]; onSelect(event: TypeaheadMatch<DataSourceType>): void { this.selectedOption = event.item; } onPreview(event: TypeaheadMatch<DataSourceType>): void { if (event) { this.previewOption = event.item; } else { this.previewOption = undefined; } } }
Min length
Minimal number of characters that needs to be entered before typeahead kicks in. When set to 0, typeahead shows on focus with full list of options.
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadMinLength]="0" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-min-length', templateUrl: './min-length.html', standalone: false }) export class DemoTypeaheadMinLengthComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Show results on blur
Use input property typeaheadHideResultsOnBlur
or config property hideResultsOnBlur
to prevent hiding typeahead's results until a user doesn't choose an item
typeaheadHideResultsOnBlur: false Model:
<button type="button" class="btn btn-primary mb-3" (click)="typeaheadHideResultsOnBlur = !typeaheadHideResultsOnBlur">Toggle typeaheadHideResultsOnBlur </button> <pre class="card card-block card-header mb-3"> typeaheadHideResultsOnBlur: {{typeaheadHideResultsOnBlur}} Model: {{selected | json}} </pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadHideResultsOnBlur]="typeaheadHideResultsOnBlur" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-show-on-blur', templateUrl: './show-on-blur.html', standalone: false }) export class DemoTypeaheadShowOnBlurComponent { typeaheadHideResultsOnBlur = false; selected?: string; states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Configuring defaults
<input [(ngModel)]="selected" [typeahead]="states" class="form-control">
import { Component } from '@angular/core'; import { TypeaheadConfig } from 'ngx-bootstrap/typeahead'; // such override allows to keep some initial values export function getTypeaheadConfig(): TypeaheadConfig { return Object.assign(new TypeaheadConfig(), { hideResultsOnBlur: false }); } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-config', templateUrl: './config.html', providers: [{ provide: TypeaheadConfig, useFactory: getTypeaheadConfig }], standalone: false }) export class DemoTypeaheadConfigComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Is first item active
Use input property typeaheadIsFirstItemActive
or config property isFirstItemActive
to make the first item active/inactive
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadIsFirstItemActive]="false" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-first-item-active', templateUrl: './first-item-active.html', standalone: false }) export class DemoTypeaheadFirstItemActiveComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Selected first item
Use typeaheadSelectFirstItem
property to make the first item in options list unselectable by tab and enter.
Model:
<pre class="card card-block card-header mb-3">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadSelectFirstItem]="false" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-selected-first-item', templateUrl: './selected-first-item.html', standalone: false }) export class DemotypeaheadSelectFirstItemComponent { selected?: string; states: string[] = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Order results
Use typeaheadOrderBy
property to order your result by a certain field and in certain direction
Source - array of string. Order direction - descending
Source - array of string. Order direction - ascending
Source - array of objects. Order direction - ascending, sort by city, group by state
Source - Observable of array of string. Order direction - descending
<div class="mb-3"> <h6>Source - <strong>array of string</strong>. Order direction - <strong>descending</strong></h6> <input [(ngModel)]="selected1" [typeahead]="states" [typeaheadOrderBy]="sortConfig1" class="form-control"> </div> <div class="mb-3"> <h6>Source - <strong>array of string</strong>. Order direction - <strong>ascending</strong></h6> <input [(ngModel)]="selected2" [typeahead]="states" [typeaheadOrderBy]="sortConfig2" class="form-control"> </div> <div class="mb-3"> <h6> Source - <strong>array of objects</strong>. Order direction - <strong>ascending</strong>, sort by <strong>city</strong>, group by <strong>state</strong> </h6> <input [(ngModel)]="selected3" [typeahead]="cities" typeaheadOptionField="city" typeaheadGroupField="state" [typeaheadItemTemplate]="customItemTemplate" [typeaheadOrderBy]="sortConfig3" class="form-control"> <ng-template #customItemTemplate let-model="item"> <span><strong>{{model.city}}</strong> - {{model.code}}</span> </ng-template> </div> <div class="mb-3"> <h6>Source - <strong>Observable of array of string</strong>. Order direction - <strong>descending</strong></h6> <input [(ngModel)]="selected4" [typeahead]="states$" [typeaheadAsync]="true" [typeaheadOrderBy]="sortConfig1" class="form-control"> </div>
import { Component, OnInit } from '@angular/core'; import { TypeaheadOrder } from 'ngx-bootstrap/typeahead'; import { Observable, of, Subscriber } from 'rxjs'; import { switchMap } from 'rxjs/operators'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-ordering', templateUrl: './ordering.html', standalone: false }) export class DemoTypeaheadOrderingComponent implements OnInit { selected1?: string; selected2?: string; selected3?: string; selected4?: string; sortConfig1: TypeaheadOrder = { direction: 'desc' }; sortConfig2: TypeaheadOrder = { direction: 'asc' }; sortConfig3: TypeaheadOrder = { direction: 'asc', field: 'city' }; states$?: Observable<string[]>; states: string[] = [ 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Alaska', 'Alabama', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; cities = [{ city: 'Norton', state: 'Virginia', code: '61523' }, { city: 'Grundy', state: 'Virginia', code: '77054' }, { city: 'Coeburn', state: 'Virginia', code: '01665' }, { city: 'Phoenix', state: 'Arizona', code: '29128' }, { city: 'Tucson', state: 'Arizona', code: '32084' }, { city: 'Mesa', state: 'Arizona', code: '21465' }, { city: 'Independence', state: 'Missouri', code: '26887' }, { city: 'Kansas City', state: 'Missouri', code: '79286' }, { city: 'Springfield', state: 'Missouri', code: '92325' }, { city: 'St. Louis', state: 'Missouri', code: '64891' }]; ngOnInit(): void { this.states$ = new Observable((observer: Subscriber<string>) => { // Runs on every search observer.next(this.selected4); }) .pipe( switchMap((token: string) => { const query = new RegExp(token, 'i'); return of( this.states.filter((state: string) => query.test(state)) ); }) ); } }
Multiple search
Set typeaheadMultipleSearch
input property to true
and provide the multiple search delimiter by typeaheadMultipleSearchDelimiters
to be able to search typeahead again after using one of the provided delimiters. Default delimiter
is ",
" if typeaheadMultipleSearchDelimiters
is not used.
After picking a first value from typeahead
dropdown, type ",
" or "|
" and then next value can be searched.
This is demo with delimeters ",
" and "|
"
Model:
<pre class="card card-block card-header">Model: {{selected | json}}</pre> <input [(ngModel)]="selected" [typeahead]="states" [typeaheadMultipleSearch]="true" typeaheadMultipleSearchDelimiters=",|" class="form-control">
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-typeahead-multiple-search', templateUrl: './multiple-search.html', standalone: false }) export class DemoTypeaheadMultipleSearchComponent { selected?: string; states = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' ]; }
Installation
ng add ngx-bootstrap --component typeahead
### Standalone component usage import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { TypeaheadModule } from 'ngx-bootstrap/typeahead'; @Component({ standalone: true, imports: [ BrowserAnimationsModule, TypeaheadModule, ... ] }) export class AppComponent(){} ### Module usage import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { TypeaheadModule } from 'ngx-bootstrap/typeahead'; @NgModule({ imports: [ BrowserAnimationsModule, TypeaheadModule, ... ] }) export class AppModule(){}
TypeaheadConfig
Default values provider for typeahead
Properties
adaptivePosition | Type: boolean Default value: false sets use adaptive position |
cancelRequestOnFocusLost | Type: boolean Default value: false if true, typeahead will cancel async request on blur |
hideResultsOnBlur | Type: boolean Default value: true used to hide results on blur |
isAnimated | Type: boolean Default value: false turn on/off animation |
isFirstItemActive | Type: boolean Default value: true used to active/inactive the first item in typeahead container |
minLength | Type: number Default value: 1 used to choose set minimal no of characters that needs to be entered before typeahead kicks-in |
selectFirstItem | Type: boolean Default value: true used to choose the first item in typeahead container |
selectItemOnBlur | Type: boolean Default value: false used to choose item on blur event |
TypeaheadOptionListContext
A context for the optionsListTemplate
input template in case you want to override default one
Properties
$implicit | Type: TypeaheadTemplateMethods Typeahead template methods |
itemTemplate | Type: TemplateRef<TypeaheadOptionItemContext> Item template |
matches | Type: TypeaheadMatch<any>[] All matches |
query | Type: string | string[] Search query |
TypeaheadOptionItemContext
A context for the typeaheadItemTemplate
input template in case you want to override default one
Properties
index | Type: number Item index |
item | Type: unknown Item |
match | Type: TypeaheadMatch<any> Typeahead match |
query | Type: string | string[] Search query |
TypeaheadTemplateMethods
Methods for optionsListTemplate
context
Methods
selectMatch | selectMatch( value: TypeaheadMatch<any>, e: Event) => void Function to select an option by click event |
selectActive | selectActive( value: TypeaheadMatch<any>) => void Function to select an option by mouseenter event |
isActive | isActive( value: TypeaheadMatch<any>) => boolean Function to check if an option is active |
Basic array
Model:
With animation
Model:
Adaptive position
Model:
Item template
Model:
List template
Model:
Option field
Model:
Async data
Model:
Async using http request
Model:
Cancel on focus lost
Model:
With delay
Model:
Template-driven forms
Model: { "address": "312 Sundown Lane", "state": null }
Reactive forms
Model: null
Grouping results
Model:
Ignore spaces and order
typeaheadSingleWords: true Model:
Phrase delimiters
Model:
Dropup
Model:
On blur
Model:
Option on blur:
Append to body
Model:
No result
Model:
Scrollable
Model:
Latinize
Model:
On select / On preview
Model:
Selected option:
Min length
Model:
Show results on blur
typeaheadHideResultsOnBlur: false Model:
Configuring defaults
Is first item active
Model:
Selected first item
Model:
Order results
Source - array of string. Order direction - descending
Source - array of string. Order direction - ascending
Source - array of objects. Order direction - ascending, sort by city, group by state
Source - Observable of array of string. Order direction - descending
Multiple search
Model:
- Basic array
- With animation
- Adaptive position
- Item template
- List template
- Option field
- Async data
- Async using http request
- Cancel on focus lost
- With delay
- Template-driven forms
- Reactive forms
- Grouping results
- Ignore spaces and order
- Phrase delimiters
- Dropup
- On blur
- Append to body
- No result
- Scrollable
- Latinize
- On select / On preview
- Min length
- Show results on blur
- Configuring defaults
- Is first item active
- Selected first item
- Order results
- Multiple search