Search code examples
typescriptangular2-services

Subscribe to Tour of Hero's Search bar results in different component


I am new to Angular 4 (I have previous experience with AngularJS) and I am attempting to wrap my brain around Observables.

I am following the Tour of Heroe's HTTP portion of the tutorial where they walk you through creating a search bar.

I have completed this successfully and have results populating in a mat-autocomplete (not in the tutorial I added this part on my own) drop down of my search bar via the simulated http.get in the service.

In an attempt to see if I understand observable's or not, I created a component called sidenav.component.ts and it is a child component of the app.component.html template.

I am attempting to put a simple for loop in a div in the sidenav.component.html component to see if I can pipe the output of that search bar into a different component template.

<div *ngFor="let hero of heros | async"></div>
  • I have registered the HeroSearchService as a provider at the app.module.ts level

and I am injecting that service into my sidenav.component.ts as follows

constructor( private heroSearchService: HeroSearchService) {}

but this is where I get confused... and my question is this.

  • If I wanted to register to the data that is populating my mat-autocomplete below my search bar, would I subscribe to the search() method in the HeroSearchService?

so you don't have to go review the code in the tutorial the service code is as follows. (with one minor change on my part, I set term to NULL to make it optional)

import { Injectable } from '@angular/core';
import { Http }       from '@angular/http';

import { Observable }     from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import { Hero }           from './hero';

@Injectable()
export class HeroSearchService {

  constructor(private http: Http) {}

  search(term: string **= null**): Observable<Hero[]> {
    return this.http
               .get(`api/heroes/?name=${term}`)
               .map(response => response.json().data as Hero[]);
  }
}

I have attempted the following in my "sidenav" component expecting to see the output of my mat-autocomplete also output in the console.log... but it does not seem to work.

    heroes: Observable<Hero[]>;

    constructor( private heroSearchService: HeroSearchService) {}

      ngOnInit() {
        this.heroes = this.heroSearchService.search()

        this.hospitals.subscribe(
        value => console.log(value)
     ) 
 }

Hoping someone can help me understand how to update both components with the output of the search() method in the HeroSearchService.


Solution

  • No, you're not understanding how that works.

    Every time you type something in your search bar, the autocomplete calls your search service with the typed value as argument, obtains a new Observable returned by the service, and subscribes to this observable to display the suggestions.

    What you're doing in your component is simply to call the service when your component is initialized, with nothing as argument (which makes little sense: you're asking for all the suggestions without even a search term), and thus obain an Observable, different from all the observables returned to the search bar when you enter something in it, and display the suggestions returned for this absence of search term.

    To do what you want to achieve (i.e. display the suggestions obtained by the search bar every time it gets some, after typing some text), you would need to expose an observable in your service, that would emit all the search results returned to the search bar. Something like that:

    export class HeroSearchService {
    
      searchResults = new Subject<Hero[]>();
    
      constructor(private http: Http) {}
    
      search(term: string **= null**): Observable<Hero[]> {
        return this.http
                   .get(`api/heroes/?name=${term}`)
                   .map(response => response.json().data as Hero[])
                   .do(heroes => this.searchResults.next(heroes));
      }
    }
    

    So, to explain, you would wiretap into the communication between the search bar and the service and emit all the search results returned to the search bar.

    And to display the same results as the search bar, you would subscribe to the searchResults observable and display the search results it emits.