Radika Moonesinghe
Radika Moonesinghe

Reputation: 489

ngbTypeahead input with Type

I have a stackblitz with a ngbTypeahead input for addresses. As you type it sends the string to the ArcGIS API, and provides a list of suggestions to populate the type ahead dropdown.

This was working with get but now I am using get<Array> since I am told it is better practice to return a type.

I have modified the service to:

@Injectable()
export class SuggestService {
  constructor(private http: HttpClient) {}

  search(term: string): Observable<Array<LocationSuggestion>> {
    if (term === "") {
      return of([]);
    }

    return this.http
      .get<Array<LocationSuggestion>>(GIS_URL, { params: GIS_PARAMS.set("text", term) });
  }
}

A sample of what is returned from the API:

    {
 "suggestions": [
  {
   "text": "Treasure Island, 3300 Las Vegas Blvd S, Las Vegas, NV, 89109, USA",
   "magicKey": "dHA9MCNsb2M9MTYzNTU4NCNsbmc9MzMjcGw9ODQ1MzAwI2xicz0xNDozNTUwMTU1NA==",
   "isCollection": false
  },
  {
   "text": "Treasure Island-Las Vegas, 3300 Las Vegas Blvd S, Las Vegas, NV, 89109, USA",
   "magicKey": "dHA9MCNsb2M9MTYzNTU4NCNsbmc9MzMjcGw9ODQ1NDkyI2xicz0xNDozNTUwMTYzMg==",
   "isCollection": false
  },
  {
   "text": "Treasure Island Parking, Mel Torme Way, Las Vegas, NV, 89109, USA",
   "magicKey": "dHA9MCNsb2M9MTYzNTU5MyNsbmc9MzMjcGw9ODQ1NjQ3I2xicz0xNDozNTUwMTYxMw==",
   "isCollection": false
  },
  {
   "text": "Treasure Island, Las Vegas, NV, 89109, USA",
   "magicKey": "dHA9MCNsb2M9MTYzNTU1MSNsbmc9MzMjcGw9ODQ0NTg2I2xicz0xNDozNTUwMTU1NA==",
   "isCollection": false
  },
  {
   "text": "Treasure Island Parking, Industrial Rd, Las Vegas, NV, 89109, USA",
   "magicKey": "dHA9MCNsb2M9MTYzNTU1MiNsbmc9MzMjcGw9ODQ0NTk4I2xicz0xNDozNTUwMTYxMw==",
   "isCollection": false
  }
 ]
}

But the actual call to the service I do not understand:

NgbTyepaheadHttp Class

 formatter = (result: any) => result.text as string;

  search = (text$: Observable<string>) => // Is text$ a observable received from input?
    text$.pipe(                           // Self explanatory
      debounceTime(300),
      distinctUntilChanged(),
      tap(() => (this.searching = true)), // Sends message to UI searching?
      switchMap(term =>                   // What does Switch Map do?
        this._service.search(term).pipe(
          tap(() => (this.searchFailed = false)),
          catchError(() => {
            this.searchFailed = true;
            return of([]);
          })
        )
      ),
      tap(() => (this.searching = false))
    );

I expect the formatter needs a type too, but when I change result:any to result:LocationSuggestion result.text is not existing?

Before I can modify the call to the service to work with a specific type - I need to understand the above code block better. It is hard to understand because of all the nesting.

Q: Which line actually returns the result of the search as the only return statement seems to be for an empty array?

I do not think the typeahead is getting an Array of LocationSuggestions because of this error in the console:

ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

Upvotes: 1

Views: 760

Answers (1)

Adrian Brand
Adrian Brand

Reputation: 21638

The call to the api returns an object that contains the array, not an array.

Change the api call to

return this.http
      .get<GisLocationSuggestions>(GIS_URL, { params: GIS_PARAMS.set("text", term) })
      .pipe(map(val => val.suggestions));

Fixed https://stackblitz.com/edit/angular-d5zmgq-r6vzye?file=src%2Fapp%2Ftypeahead-http.ts

Upvotes: 1

Related Questions