Search code examples
angularasynchronousionic3observableangular-pipe

Observable async pipe


I'm attaching an Observable (menuitems$) in my AppComponent using:

<h2 *ngFor="let menuitem of menuitems$ | async">DEFAULT TEXT</h2>

In my AppComponent's .ts file I create the menuitems Observable:

this.menuitems$ = this.wordPressMenuService.getMenu(2).map(m => m.items);

And in my AppComponent's .ts file I subscribe again using:

this.menuitems$.subscribe(menuitems => { console.log(menuitems); });

The .subscribe returns data and logs it into the console, but binding it with the Async-pipe to the H2-tag (also tried different tags) does not render the h2-tags on the screen. No (console) error output.

My MenuService looks like this:

protected readonly menus$ = new Subject<WordPressMenu>();

constructor(private dataService:DataService) { }

getMenu(id:number) : Observable<WordPressMenu> {
    this.dataService.get<WordPressMenu>(AppSettings.WP_MENU_ENDPOINT + id).subscribe(data => {
        this.menus$.next(data);
    });
    return this.menus$.filter(m => m.ID == id);
}

Update: It works when I remove the subscribe(), but still didn't find out why you can't subscribe to the same observable with subscribe() and template-binding. So using the code below works, but why does it have to be a seperate Observable?

this.menuitems1$ = this.wordPressMenuService.getMenu(2).map(m => m.items);
this.menuitems2$ = this.wordPressMenuService.getMenu(2).map(m => m.items);

Solution

  • What is happening is your dataService.get().subscribe in your getMenu method is finishing before the async pipe subscribes. So the async pipe never receives the subject's emissions. If possible, I would avoid using the subject and just return the get observable

    getMenu(id:number) : Observable<WordPressMenu> {
        return this.dataService.get<WordPressMenu>(AppSettings.WP_MENU_ENDPOINT + id)
            .map(data => data.filter(m => m.ID == id));
        });
    }