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

Angular 11 – How to pass data observable using a service

My goal is to pass an observable from a parent component to its children, I can’t do it using "Input" and "Output" because the component that contains the child components is itself a component of an internal library for user interfaces.

I have a father component: home.componente.ts

In the parent component HomeComponent, I call a service from the OnInit event and store its response in a "Subject" type to store an observable so I can subscribe to child components:

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

this.tabs = [            
   {id: 'reportsTab', label: 'Files', routerLink: '/reports/1'},
   {id: 'processesTab', label: 'Tasks', routerLink: '/processes/1'},
];
ngOnInit(): void {
    this.processesService.getInfo(id).subscribe(response => { 
        this.processesService.data.next(response);
    });
}

This is the processes.service.ts service:

export class ProcessesService {
    data: Subject<RestResponse<ScheduleDataOutput[]>> = new Subject();
    
    public getInfo(id: number): Observable<RestResponse<ScheduleDataOutput[]>> {
      let serviceName = "/processes/info";
      if (id) {
        serviceName = serviceName + '?id=' + id;
      }
      return this.service.get<any>(serviceName)
      .pipe(
        tap(_ => this.log('fetched info')),
        catchError(this.handleError<ScheduleDataOutput[]>('getInfo', []))
      );
    }
    
    getData() {
        return this.data.asObservable()
    }
}

In the home.component.html file, we have the inner component, it’s a UI component for to use the classic sistem of tabs, and each tab is a child component:

<app-menu-tab [tabs]="tabs"></app-menu-tab>

When, I click on a tab, it has a routerLink that loads the child components, to which I want to pass the response (observable) obtained in HomeComponent, subscribe to the observable in the child component and with that response paint a Datagrid in the child components.

When refreshing the screen if I correctly load the Datagrids of the childs components with the response obtained in the HomeComponent component, the problem is that when I click on the tabs the Datragrids are not loaded.

This is the OnInit event of the "reportsTab" tab component:

ngOnInit(): void {
    // Here I access
    this.reportsSubscription = this.processesService.getData().subscribe(response => {
        // But within the subscription I do not access.
        console.log("response: ", response)
    });
}

The issue is that I cannot access within the subscription, at some point the observable was misconfigured, the same happens with the child component of the "processesTab" tab, when I click on the tab, I cannot access the subscription of the observable:

ngOnInit(): void {
    // Here I access
    this.tasksSubscription = this.processesService.getData().subscribe(response => {
        // But within the subscription I do not access.
        console.log("response: ", response)
    });
}

What could be the problem? If I am passing the observable to the childs components, but it only works and loads the Datagrids, when I reload the page, but if I click on the tabs, I lose the response obtained in the HomeComponent and the Datagrids appear empty.

>Solution :

You need to use a BehaviorSubject (or a ReplaySubject if you don’t need an initial value), not a plain Subject.

The BehaviorSubject will emit the latest value to new subscribers, while Subject won’t do that.

In order for a subscriber to get the data emitted from a subject, it needs to be subscribed to it prior to the data being emitted.

In short, the data property should look like this:

data = new BehaviorSubject<RestResponse<ScheduleDataOutput[]>>(null);

Or, if the initial value is superfluous, you could go with a ReplaySubject instead:

data = new ReplaySubject<RestResponse<ScheduleDataOutput[]>>(1);
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