Ngx-bootstrap: Typeahead with async http REST request

Created on 9 Mar 2016  路  7Comments  路  Source: valor-software/ngx-bootstrap

Can someone post me an example of how to do a typeahead with a REST service as source in Typescript? Do I need to use a promise or can I use observables? Specifically I am looking for what I need in the getAsyncData() function from the example here: http://valor-software.com/ng2-bootstrap/

Rest Response:

[{id: 1, name: 'Alabama'}, {id: 2, name: 'Alaska'}, {id: 3, name: 'Arizona'},{id: 4, name: 'Arkansas'}, {id: 5, name: 'California'}]

What I have (doesn't work):

public getAsyncData(context:any):Function {
        if (this._prevContext === context) {
            return this._cache;
        }
        this._prevContext = context;
        let f:Function = function (http:Http) {
            let searchParams = new URLSearchParams();
            searchParams.set('search', context.asyncSelected);
            http.get('http://mydomain.com/search', {search: searchParams})
                    .subscribe(res => {
                        context.companies = res.json();
                    });
        };
        this._cache = f(this.http);
        return this._cache;
}

Everything else is like in the example here: http://valor-software.com/ng2-bootstrap/

Any help is greatly appreciated. Thank you.

Most helpful comment

I had the same question yesterday and here's how I solved it.

In the template, notice the change to the [typeahead] function reference. This is to ensure that Angular does not trigger the call to this function on each change detection:

<input class="form-control"
             type="text"
             [(ngModel)]="arrivalLocation"
             [typeahead]="autoCompleteRef"
             [typeaheadOptionField]="'name'"
             [typeaheadWaitMs]="100"
             [typeaheadMinLength]="3">

Then in my component's class, I declare this reference and bind it to my component:

public autoCompleteRef = this.autoComplete.bind(this);

Finally, the method using Observables:

public autocomplete() {

    return this.http.get(`[...what you need to get...]`)
      .map(r=>r.json())
      .map( [...other mapping you may need... ] )
      .toPromise();
}

Note: I had to use something like this to match as my other mapping to match the format expected:

.map( (el)=>{return el.map((data)=>{return({id:data.value,name:data.label});})

Hope this helps!

All 7 comments

I had the same question yesterday and here's how I solved it.

In the template, notice the change to the [typeahead] function reference. This is to ensure that Angular does not trigger the call to this function on each change detection:

<input class="form-control"
             type="text"
             [(ngModel)]="arrivalLocation"
             [typeahead]="autoCompleteRef"
             [typeaheadOptionField]="'name'"
             [typeaheadWaitMs]="100"
             [typeaheadMinLength]="3">

Then in my component's class, I declare this reference and bind it to my component:

public autoCompleteRef = this.autoComplete.bind(this);

Finally, the method using Observables:

public autocomplete() {

    return this.http.get(`[...what you need to get...]`)
      .map(r=>r.json())
      .map( [...other mapping you may need... ] )
      .toPromise();
}

Note: I had to use something like this to match as my other mapping to match the format expected:

.map( (el)=>{return el.map((data)=>{return({id:data.value,name:data.label});})

Hope this helps!

For me, it does not work :(
can you help me ?
I get an error: EXCEPTION: TypeError: _this.typeahead(...) is undefined

My Component:

public autoRef = this.getVehicleInformation.bind(this);

public getVehicleInformation(): any {
    return this.vehicleService.getVehicleInformation(this.vehicleInformation).toPromise;
}

Markup:

<input id="vehicle" placeholder="Example: All New Honda Civic" class="form-control" autocomplete="off" [(ngModel)]="vehicleInformation" [typeahead]="autoRef" [typeaheadOptionField]="'value'" [typeaheadWaitMs]="100" [typeaheadMinLength]="2"
                       (typeaheadLoading)="changeVehicleInfoLoading($event)"
                       (typeaheadNoResults)="changeVehicleInfoNoResults($event)"
                       (typeaheadOnSelect)="onSelectVehicleInfo($event)" >

According with last source code, promise don't work with typeahead anymore. Only Observable.

Example:

<input class="form-control" [(ngModel)]="selectedNumber" [typeahead]="filteredNumbers$" (typeaheadNoResults)="setInvalidNumber($event)" (typeaheadOnSelect)="showNumber($event.item)" [typeaheadOptionsLimit]="10" [typeaheadWaitMs]="500">

filteredNumbers$: Observable<string[]>;
invalidNumber: boolean = false;
selectedNumber: string = '';

ngOnInit(): void {
  this.filteredNumbers$ = Observable.create((observer: Observer<string>) => observer.next(this.selectedNumber)).mergeMap((number: string) => ...);
}

setInvalidNumber(invalidNumber: boolean): void {
  ...
}

showNumber(number: string): void {
  ...
}

Hello @Martin-Wegner ,

The above code will produce options.slice is not a function exception.
There is some sort of issue with typeahead binding to the result that comes from the server.

Is it possible that you provide an example where typeahead is getting the data from real service (not hard-coded array that exists in the component or a static json file on the server)?

I think type ahead has a similar issue as it used to have during Angular RC4 where there is a problem with binding to data that comes from the service.

Thank you for your time

@binarydigits

Example:

<input [(ngModel)]="selectedNumber" [typeahead]="filteredNumbers$" (typeaheadNoResults)="setInvalidNumber($event)" (typeaheadOnSelect)="showNumber($event.item)" [typeaheadOptionsLimit]="10" [typeaheadWaitMs]="500">

filteredNumbers$: Observable<string[]>;
invalidNumber: boolean = false;
selectedNumber: string = '';

constructor(private yourRestService: YourRestService) {}

ngOnInit(): void {
  this.filteredNumbers$ = Observable.create((observer: Observer<string>) => observer.next(this.selectedNumber))
    .mergeMap((number: string) => this.yourRestService.getNumbersStartsWith(countingPointNumber));
}

setInvalidNumber(invalidNumber: boolean): void {
  ...
}

showNumber(number: string): void {
  ...
}

Hi everyone,

The type ahead works as specified in documentation with the latest upgrade of angular to 2.3 and ng2-bootstrap to 1.1.16-9.

Thank you so much for the effort to develop ng2-bootstrap!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

phmello picture phmello  路  3Comments

RolfVeinoeSorensen picture RolfVeinoeSorensen  路  3Comments

mounthorse-slns picture mounthorse-slns  路  3Comments

juanitavollmering picture juanitavollmering  路  3Comments

ravirajhalli picture ravirajhalli  路  3Comments