<h4>Asynchronous results</h4>
<pre class="card card-block card-header">Model: {{asyncSelected | json}}</pre>
<input [(ngModel)]="asyncSelected"
[typeahead]="dataSource"
(typeaheadLoading)="changeTypeaheadLoading($event)"
(typeaheadNoResults)="changeTypeaheadNoResults($event)"
(typeaheadOnSelect)="typeaheadOnSelect($event)"
[typeaheadOptionsLimit]="1"
[typeaheadOptionField]="'email'"
placeholder="Locations loaded with timeout"
class="form-control">
<div *ngIf="typeaheadLoading===true">
<i class="glyphicon glyphicon-refresh ng-hide" style=""></i>
<div *ngIf="typeaheadNoResults===true" class="" style="">
<i class="glyphicon glyphicon-remove"></i> No Results Found
@valorkin
Hi everyone, I have the same issue with the same syntax. Tried several ways to do it.
I skipped some of the methods/properties in order to make it more clear.
Note: The service returns the array of Schools and component successfully subscribes to it.
When observer.next(result); is executed, the Error gets thrown: EXCEPTION: options.slice is not a function
NOTE 2: I know that in Angular RC4, we had to have a hack to make it work with the service that gets the data for typeahead. The hack was as follows:
The HTML markup
<input [disabled]="!IsFormAuthorized" id="School" name="School" [(ngModel)]="asyncSelected" [typeahead]="autoCompleteRef"
Component code (
public autoCompleteRef = this.getAsyncData.bind(this); //getAsynData returned promise <School[]>
May be something similar can be done with the service that returns observable?
core.umd.js:3010 TypeError: options.slice is not a function
at TypeaheadDirective.prepareMatches (ng2-bootstrap.umd.js:5376)
at TypeaheadDirective.finalizeAsyncCall (ng2-bootstrap.umd.js:5358)
at SafeSubscriber.eval [as _next] (ng2-bootstrap.umd.js:5314)
at SafeSubscriber.__tryOrUnsub (Subscriber.ts:238)
at SafeSubscriber.next (Subscriber.ts:190)
at Subscriber._next (Subscriber.ts:135)
at Subscriber.next (Subscriber.ts:95)
at MergeMapSubscriber.notifyNext (mergeMap.ts:144)
at InnerSubscriber._next (InnerSubscriber.ts:17)
at InnerSubscriber.Subscriber.next (Subscriber.ts:95)ErrorHandler.handleError @ core.umd.js:3010next @ core.umd.js:6654schedulerFn @ core.umd.js:5952SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:5944NgZone.triggerError @ core.umd.js:6248onHandleError @ core.umd.js:6227ZoneDelegate.handleError @ zone.js:207Zone.runTask @ zone.js:139ZoneTask.invoke @ zone.js:304
Subscriber.ts:241 Uncaught TypeError: options.slice is not a functionTypeaheadDirective.prepareMatches @ ng2-bootstrap.umd.js:5376TypeaheadDirective.finalizeAsyncCall @ ng2-bootstrap.umd.js:5358(anonymous function) @ ng2-bootstrap.umd.js:5314SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95MergeMapSubscriber.notifyNext @ mergeMap.ts:144InnerSubscriber._next @ InnerSubscriber.ts:17Subscriber.next @ Subscriber.ts:95(anonymous function) @ locations.component.ts:226SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95MapSubscriber._next @ map.ts:84Subscriber.next @ Subscriber.ts:95Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95onLoad @ http.umd.js:1083ZoneDelegate.invokeTask @ zone.js:236onInvokeTask @ core.umd.js:6197ZoneDelegate.invokeTask @ zone.js:235Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
MY CODE SAMPLE
Module Code Snippet
`import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TypeaheadModule } from 'ng2-bootstrap/ng2-bootstrap';
//component and routing module
import { LocationsComponent } from './locations.component';
import { LocationsRoutingModule } from './locations-routing.module';
import { SchoolService } from '../school/schoolService';
@NgModule({
imports: [
CommonModule,
LocationsRoutingModule,
FormsModule,
TypeaheadModule
declarations: [
LocationsComponent
providers: [
SchoolService
exports: [CommonModule]
export class LocationsModule { }`
Component Code Snippet
@component({
selector: 'locations-form',
templateUrl: './locations.html'
export class LocationsComponent implements OnInit {
` public dataSource: Observable;
constructor(private _schoolService: SchoolService,) {
this.dataSource = Observable.create((observer: any) => {
return this._schoolService.getSchools4(this.asyncSelected)
.subscribe((result: any) => {
observer.next(result); //this line fails; result contains array of schools
HTML Template Code Snippet
<input [disabled]="!IsFormAuthorized" id="School" name="School" [(ngModel)]="asyncSelected" [typeahead]="dataSource" [typeaheadOptionField]="'Name'" (typeaheadLoading)="changeTypeaheadLoading($event)" (typeaheadNoResults)="changeTypeaheadNoResults($event)" (typeaheadOnSelect)="typeaheadOnSelect($event)" class="form-control" required>
Service Code Snippet
` getSchools4(query: string): Observable {
return this.http.get(this._userAPIUrl + '/' + query)
.map(this.extractData)
.catch(this.handleError);
private extractData(res: Response) {
let body = res.json();
return body || {};
private handleError(error: Response) {
// in a real world app, we may send the error to some remote logging infrastructure
// instead of just logging it to the console
console.error(error);
return Observable.throw(error.json().error || 'Server error');
School Class Code Snippet
export class School { constructor( public OrganizationId: number, public Name: string ) { } }
I don't think you have your data source setup properly. From the documentation
this.dataSource = Observable.create((observer:any) => {
// Runs on every search
// asyncSelected is a component variable bound to [(ngModel)]
// when user types into the input .next is called with the value from the input
observer.next(this.asyncSelected);
}).mergeMap((term: string) => this.myAsyncDataService.search(term));
Make sure you have that last mergeMap and that your service returns an array.
In case this will help others... I was also receiving "options.slice is not a function", and the issue was the way I implemented the async service returning my array of objects in Angular4.
I forgot to map my response to json in the service (Angular1 habits die hard) like this:
getList(listName:string, query:string): Observable<any> { return this.http.get(
${this.apiUrl}/${listName}?query=${query}); }
Once I changed it to this, the "options.slice" problem was resolved.
getList(listName:string, query:string): Observable<any> { return this.http.get(
${this.apiUrl}/${listName}?query=${query}) .map((res: Response) => res.json()) .catch((error:any) => Observable.throw(error.json().error || 'Server error')); }
I checked in the ngx-bootstrap library typeahead.directive.js line 259, and noticed that the limited variable was just a truncated string like '[{ "foo:', and realized the response was not converted to a json object, but was merely a string.
Following @avalonabecker, here's another example
getStatesAsObservable(token: string): Observable<any> {
const query = new RegExp(token, 'ig');
const fn = () => {
return new Observable((observer) => {
setTimeout(() => {
const res = this.statesComplex.filter((state: any) => {
return query.test(state.name);
observer.next(res);
}, 1000);
return fn();