Búsqueda de sitios web

angular - ngBootstrap typeahead da como resultado Error: No se puede encontrar un diferenciador que soporte el objeto '[object Promise]' de tipo 'object'


Tengo un problema al usar el typeahead de ngBootstrap con solicitudes HTTP asincrónicas.

Lo que tengo es

ejemplo.html

<input id="typeahead-basic" type="text" class="form-control" value="{{issue.Series.Title}}" (selectItem)="selectSeries($event)" [ngbTypeahead]="searchSeries" [resultFormatter]="seriesFormatter"/>

ejemplo.ts

searchSeries = (text$: Observable<string>) =>
        text$
            .debounceTime(100)
            .distinctUntilChanged()
            .map(async term => {
                return await this.service.getSeries(term);
            });

example.servicios.ts

  async getSeries(term: string): Promise<Series[]> {
    let series: Series = new Series();
    series.Title = term;

    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    let options = new RequestOptions({headers: headers});

    return await this.http.post(this.urlSeries, JSON.stringify(series), options)
        .map(res => res.json() || {})
        .catch(res => Observable.throw("error"))
        .toPromise();
  }    

Cada vez que empiezo a escribir un valor en el campo de entrada, recibo el siguiente error.

NgbTypeaheadWindow.html:5 ERROR Error: Cannot find a differ supporting object '[object Promise]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
    at NgForOf.webpackJsonp.../../../common/@angular/common.es5.js.NgForOf.ngOnChanges (common.es5.js:1659)
    at checkAndUpdateDirectiveInline (core.es5.js:10891)
    at checkAndUpdateNodeInline (core.es5.js:12382)
    at checkAndUpdateNode (core.es5.js:12321)
    at debugCheckAndUpdateNode (core.es5.js:13180)
    at debugCheckDirectivesFn (core.es5.js:13121)
    at Object.eval [as updateDirectives] (NgbTypeaheadWindow.html:5)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13106)
    at checkAndUpdateView (core.es5.js:12288)
    at callViewAction (core.es5.js:12651)

Hasta donde entiendo, el mensaje de error indica que ngFor necesita un Array para funcionar. Mi problema con ese mensaje de error es que searchSeries sí devuelve un arreglo. Si cambio searchSeries a

searchSeries = (text$: Observable<string>) =>
        text$
            .debounceTime(100)
            .distinctUntilChanged()
            .map(async term => {
                let result = await this.service.getSeries(term);
                console.log(result);
                return result;
            }); 

Puedo ver que ese resultado contiene un arreglo. ¿Pero por qué recibo este mensaje de error?

¡Gracias de antemano!

Respuesta #1

Primero que todo, prefiero que uses RXJS con observable. Sobre el mensaje de error: el problema está en la línea: let result=await this.service.getSeries(term); el resultado ahora es un observable, así que no puedes iterar sobre él. Si estás tratando de solucionar esto sin cambiar la implementación, simplemente espera a que la solicitud HTTP termine y luego establece el resultado dentro de ella. Si estás usando los observables, necesitas algo como YOURREQUEST.subscribe(data => { let result=data }); pero en realidad yo no he probado Angular con promesas. También te sugiero que veas el ejemplo en la página de demostración de ngbootstrap "Wikipedia search" https://ng-bootstrap.github.io/#/components/typeahead. Espero que me entiendas y disculpa por mi mal inglés.

Respuesta #2

El operador switchMap debería poder ayudarte aquí. Del ejemplo de Ng-bootstrap:

search = (text$: Observable<string>) =>
    text$
      .debounceTime(300)
      .distinctUntilChanged()
      .do(() => this.searching = true)
      .switchMap(term =>
        this._service.search(term)
          .do(() => this.searchFailed = false)
          .catch(() => {
            this.searchFailed = true;
            return Observable.of([]);
          }))
      .do(() => this.searching = false)
      .merge(this.hideSearchingWhenUnsubscribed);