diff --git a/demo/src/app/components/+typeahead/demos/async/async.html b/demo/src/app/components/+typeahead/demos/async/async.html
index bf21cad553..b06ac96294 100644
--- a/demo/src/app/components/+typeahead/demos/async/async.html
+++ b/demo/src/app/components/+typeahead/demos/async/async.html
@@ -1,12 +1,8 @@
-
+
-Loading
diff --git a/demo/src/app/components/+typeahead/demos/async/async.ts b/demo/src/app/components/+typeahead/demos/async/async.ts
index b06009a664..81f47581ec 100644
--- a/demo/src/app/components/+typeahead/demos/async/async.ts
+++ b/demo/src/app/components/+typeahead/demos/async/async.ts
@@ -1,8 +1,12 @@
import { Component } from '@angular/core';
import { Observable, of } from 'rxjs';
-import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
-import { mergeMap } from 'rxjs/operators';
+
+interface DataSourceType {
+ id: number;
+ name: string;
+ region: string;
+}
@Component({
selector: 'demo-typeahead-async',
@@ -10,10 +14,8 @@ import { mergeMap } from 'rxjs/operators';
})
export class DemoTypeaheadAsyncComponent {
asyncSelected: string;
- typeaheadLoading: boolean;
- typeaheadNoResults: boolean;
- dataSource: Observable;
- statesComplex: any[] = [
+ dataSource: Observable;
+ statesComplex: DataSourceType[] = [
{ id: 1, name: 'Alabama', region: 'South' },
{ id: 2, name: 'Alaska', region: 'West' },
{ id: 3, name: 'Arizona', region: 'West' },
@@ -67,30 +69,6 @@ export class DemoTypeaheadAsyncComponent {
];
constructor() {
- this.dataSource = Observable.create((observer: any) => {
- // Runs on every search
- observer.next(this.asyncSelected);
- })
- .pipe(
- mergeMap((token: string) => this.getStatesAsObservable(token))
- );
- }
-
- getStatesAsObservable(token: string): Observable {
- const query = new RegExp(token, 'i');
-
- return of(
- this.statesComplex.filter((state: any) => {
- return query.test(state.name);
- })
- );
- }
-
- changeTypeaheadLoading(e: boolean): void {
- this.typeaheadLoading = e;
- }
-
- typeaheadOnSelect(e: TypeaheadMatch): void {
- console.log('Selected value: ', e.value);
+ this.dataSource = of(this.statesComplex);
}
}
diff --git a/src/spec/typeahead.directive.spec.ts b/src/spec/typeahead.directive.spec.ts
index 36ebcb2437..6f627278db 100644
--- a/src/spec/typeahead.directive.spec.ts
+++ b/src/spec/typeahead.directive.spec.ts
@@ -5,8 +5,9 @@ import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
-import { dispatchMouseEvent, dispatchTouchEvent, dispatchKeyboardEvent } from '@netbasal/spectator';
import { of } from 'rxjs';
+import { dispatchMouseEvent, dispatchTouchEvent, dispatchKeyboardEvent } from '@netbasal/spectator';
+
import { TypeaheadMatch, TypeaheadDirective, TypeaheadModule } from '../typeahead';
interface State {
@@ -102,9 +103,8 @@ describe('Directive: Typeahead', () => {
expect(directive.typeaheadSelectFirstItem).toBeTruthy();
});
- it('should typeaheadAsync to false, if typeahead is an observable', () => {
+ it('should typeaheadAsync to true, if typeahead is an observable', () => {
directive.typeahead = of(component.states);
-
directive.ngOnInit();
expect(directive.typeaheadAsync).toBeTruthy();
@@ -345,6 +345,19 @@ describe('Directive: Typeahead', () => {
})
);
+ it('should result in 2 item matches, when "Ala" is entered in async mode', fakeAsync(() => {
+ directive.typeahead = of(component.states);
+ directive.ngOnInit();
+ inputElement.value = 'Ala';
+ // fireEvent(inputElement, 'input');
+ dispatchTouchEvent(inputElement, 'input');
+ fixture.detectChanges();
+ tick(100);
+
+ expect(directive.matches.length).toBe(2);
+ })
+ );
+
it('should result in 0 matches, when input does not match', fakeAsync(() => {
inputElement.value = 'foo';
dispatchTouchEvent(inputElement, 'input');
diff --git a/src/typeahead/typeahead.directive.ts b/src/typeahead/typeahead.directive.ts
index 4fd7e2034b..44a0c28584 100644
--- a/src/typeahead/typeahead.directive.ts
+++ b/src/typeahead/typeahead.directive.ts
@@ -22,7 +22,7 @@ import { TypeaheadContainerComponent } from './typeahead-container.component';
import { TypeaheadMatch } from './typeahead-match.class';
import { TypeaheadConfig } from './typeahead.config';
import { getValueFromObject, latinize, tokenize } from './typeahead-utils';
-import { debounceTime, filter, mergeMap, switchMap, toArray } from 'rxjs/operators';
+import { debounceTime, filter, map, mergeMap, switchMap, toArray } from 'rxjs/operators';
@Directive({selector: '[typeahead]', exportAs: 'bs-typeahead'})
export class TypeaheadDirective implements OnInit, OnDestroy {
@@ -53,7 +53,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy {
* contains the group value, matches are grouped by this field when set.
*/
@Input() typeaheadGroupField: string;
- /** should be used only in case of typeahead attribute is array.
+ /** should be used only in case of typeahead attribute is Observable of array.
* If true - loading of options will be async, otherwise - sync.
* true make sense if options array is large.
*/
@@ -389,7 +389,18 @@ export class TypeaheadDirective implements OnInit, OnDestroy {
this.keyUpEventEmitter
.pipe(
debounceTime(this.typeaheadWaitMs),
- switchMap(() => this.typeahead)
+ switchMap((value: string) => {
+ return this.typeahead
+ .pipe(
+ // tslint:disable-next-line:no-any
+ map((typeahead: any[]) => {
+ const normalizedQuery = this.normalizeQuery(value);
+
+ return typeahead.filter((option: any) =>
+ option && this.testMatch(this.normalizeOption(option), normalizedQuery));
+ })
+ );
+ })
)
.subscribe((matches: TypeaheadMatch[]) => {
this.finalizeAsyncCall(matches);
@@ -408,11 +419,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy {
return from(this.typeahead)
.pipe(
filter((option: TypeaheadMatch) => {
-
- return (
- option &&
- this.testMatch(this.normalizeOption(option), normalizedQuery)
- );
+ return option && this.testMatch(this.normalizeOption(option), normalizedQuery);
}),
toArray()
);