Search code examples
restangularobservabletypeaheadng2-bootstrap

How to use ng2-bootstrap Typahead with REST backend


How do I 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 at the ng2-bootstrap homepage.

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):

home.ts

import {Component} from 'angular2/core';
import {CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/common';
import {TYPEAHEAD_DIRECTIVES} from '../../../ng2-bootstrap';
import {Http,URLSearchParams,Headers} from 'angular2/http';

// webpack html imports
let template = require('./typeahead-demo.html');

@Component({
    selector: 'typeahead-demo',
    directives: [TYPEAHEAD_DIRECTIVES, CORE_DIRECTIVES, FORM_DIRECTIVES],
    template: template
})

export class TypeaheadDemo {
  public selected:string = '';
  public asyncSelected:string = '';
  public typeaheadLoading:boolean = false;
  public typeaheadNoResults:boolean = false;
  public states:Array<string> = [];
  public statesComplex:Array<any> = [];

  public getContext() {
    return this;
  }

  public _cache:any;
  public _prevContext:any;

  public constructor(public http:Http) {}

   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://example.com/search', {search: searchParams})
                    .subscribe(res => {
                        context.states = res.json();
                    });
        };
        this._cache = f(this.http);
        return this._cache;
  }

  public changeTypeaheadLoading(e:boolean) {
    this.typeaheadLoading = e;
  }

  public changeTypeaheadNoResults(e:boolean) {
    this.typeaheadNoResults = e;
  }

  public typeaheadOnSelect(e:any) {
    console.log(`Selected value: ${e.item}`);
  }
}

home.html

<div class='container-fluid'>
<pre>Model: {{asyncSelected | json}}</pre>
<input [(ngModel)]="asyncSelected"
       [typeahead]="getAsyncData(getContext())"
       (typeaheadLoading)="changeTypeaheadLoading($event)"
       (typeaheadNoResults)="changeTypeaheadNoResults($event)"
       (typeaheadOnSelect)="typeaheadOnSelect($event)"
       [typeaheadOptionsLimit]="7"
       placeholder="Locations loaded with timeout"
       class="form-control">
<div [hidden]="typeaheadLoading!==true">
    <i class="glyphicon glyphicon-refresh ng-hide" style=""></i>
</div>
<div [hidden]="typeaheadNoResults!==true" class="" style="">
    <i class="glyphicon glyphicon-remove"></i> No Results Found
</div>


Solution

  • I was able to get it working thanks to a reply on github from yannickadam:

    home.ts

    ...
    public autoCompleteRef = this.autoComplete.bind(this);
    
    public autoComplete() {
        let headers = new Headers();
        headers.append('Authorization', 'Bearer ' + this.authservice.getToken());
    
        let searchParams = new URLSearchParams();
        searchParams.set('search', this.autoCompleteSearchTerm);
    
        return this.http.get(this.api_url, {search: searchParams, headers: headers})
            .map(res => res.json())
            .map((el)=> {
                return el.map((data)=> {
                    return ({id: data.id, name: data.name}); // unnecessary as format is the same in this case
                });
            })
            .toPromise();
    }
    ...
    

    html.html

    <input class="form-control"
           [(ngModel)]="autoCompleteSearchTerm"
           [typeahead]="autoCompleteRef"
           [typeaheadOptionField]="'name'"
           [typeaheadWaitMs]="300"
           [typeaheadMinLength]="1"
           (typeaheadOnSelect)="typeaheadOnSelect($event)">