Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Input Subject is empty in child component Angular 17

I am trying to pass data from a parent to its child component in Angular 17.
The data is retrieved from the back-end through an API that gets an array of items.

In my parent component, items$ is a subject:

items$ = Subject<Array<Item>> = new Subject();

I subscribe it to the method of my service that retrieves all items from the backend:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

ngOnInit(){
    this.itemService.getItems().subscribe(this.items$);
}

In my parent.html template, this code does display that there are items:

@if(items$ | async){
"There are items!"
}@else{
"There aren't any items"
}

So I then call my child component:

@if(items$ | async){
<app-child [items$]=items$>
}

This is what my child.component.ts looks like:

export class ChildComponent implements OnInit{
@Input() items$: Observable<Array<Item>>;

ngOnInit(){
this.items$.subscribe();
}
}

An child.component.html:

@if(items$ | async){
"There are items in the child component!"
}@else{
"There aren't any items in the child component"
}

Well, it displays that there aren’t any items in the child component.

I know I don’t need to subscribe in the onInit() method of my child component, but I really just wanted to make sure that I am indeed subscribed to my multicast observable.

Also, interestingly, when I take my child component out of the @if condition in parent.html, the items are displaying!

Any idea why? And how can I condition the display of my child component to the presence of items?

>Solution :

You can convert the Subject to a BehaviorSubject, so that it maintains state (the array). Prefer subject when you want to trigger emissions for events (Event Bus) not holding state.

Also you should write a callback inside the subscribe that calls the next method of the BehaviorSubject with the data from the API.

itemService = inject(ItemService);
items$: BehaviorSubject<Array<any> | null> =
  new BehaviorSubject<Array<any> | null>(null);

ngOnInit() {
  this.itemService.getItems().subscribe((data: any) => {
    this.items$.next(data);
  });
}

Full Code:

import { Component, inject, Injectable, Input, OnInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { Observable, of, Subject, BehaviorSubject } from 'rxjs';
import { CommonModule } from '@angular/common';

@Injectable({ providedIn: 'root' })
export class ItemService {
  getItems() {
    return of([{ test: 1 }]);
  }
}

@Component({
  selector: 'app-child',
  imports: [CommonModule],
  template: `
    @if(items$ | async) {
      "There are items in the child component!"
    } @else {
      "There aren't any items in the child component"
    }
  `,
})
export class ChildComponent implements OnInit {
  @Input() items$!: Observable<Array<any> | null>;

  ngOnInit() {
    this.items$.subscribe();
  }
}

@Component({
  selector: 'app-root',
  imports: [CommonModule, ChildComponent],
  template: `
    @if(items$ | async){
      "There are items!"
    }@else{
      "There aren't any items"
    }
    <hr/>
    @if(items$ | async) {
      <app-child [items$]="items$"/>
    }
  `,
})
export class App {
  itemService = inject(ItemService);
  items$: BehaviorSubject<Array<any> | null> =
    new BehaviorSubject<Array<any> | null>(null);

  ngOnInit() {
    this.itemService.getItems().subscribe((data: any) => {
      this.items$.next(data);
    });
  }
}

bootstrapApplication(App);

Stackblitz Demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading