Home > OS >  passed data from a component shows undefined in another one
passed data from a component shows undefined in another one

Time:11-09

I have two component and a service to transfer data here is my service:

import { Injectable } from '@angular/core';
 @Injectable({
  providedIn: 'root'
  })
export class DataService {

public sharedData:any;
constructor() { }
}

i injected service to both components ,here is my first service which sends data:

constructor(private http:HttpClient,private dataService:DataService)
{ }


    this.http.post("backendURL",quote).subscribe(s=>{
     this.dataService.sharedData=s;
         }

here is my second component that consumes the service:

     public modaldata:any;
     constructor(private dataServce:DataService) {  }

i just want to alert the data but it shows undefiend:

  ngOnInit(): void {
 alert(this.dataServce.sharedData);
                   }

any idea?thanks in advance

CodePudding user response:

try to set data below way also you can use behaviourSubject() and viewChild()

DataService.ts

sharedData: any;

getData(){
    return this.sharedData;
}

setData(data){
    this.sharedData = data;
}

set data component.ts

this.http.post("backendURL",quote).subscribe(s=>{
    this.dataService.setData(s);
  }

get data to other component

 ngOnInit(): void {
      const data = this.dataService.getData();
      console.log(data);
  }

CodePudding user response:

The issue with this approach is that when you try to show the sharedData using the alert, the API call is not yet completed.

What is awesome in Angular (and not only, you can use it with multiple other libraries and frameworks) is RXJS. By leveraging the power of observables and subjects, you can get pass this racing condition issue.

Try to turn sharedData into a BehaviorSubject for example, and you can then do something like this:

@Injectable({
  providedIn: 'root',
})
export class DataService {
  private sharedDataSubject = new BehaviorSubject<any>(null);

  public sharedData$: Observable<any>;

  constructor() {
    this.sharedData$ = this.sharedDataSubject.asObservable();
  }

  public updateSharedData(data: any): void {
    this.sharedDataSubject.next(data);
  }
}

When your data is available, you can update the shared data like this:

this.http.post("backendURL", quote).subscribe(data => {
  this.dataService.updateSharedData(data);
});

And to consume it, you only need to subscribe to that public observable:

ngOnInit(): void {
  this.dataService.sharedData$.pipe(
    filter(data => !!data) // filter out the first null value
    // or replace the BehaviorSubject with Subject if you do not need a default value
  ).subscribe(data => {
    alert(this.dataServce.sharedData);
  });
}

There's a caveat though. For the observables that you create, you also need to manage the subscription in order not to create memory leaks. If you subscribe to this observable in your component, then you also need to unsubscribe when the component gets destroyed. Alternatively, you can use the async pipe in your template to render the data, and then you don't need to manually take care of the subscription.

In the consuming component (the one that does the subscribe) you need to store the subscription somewhere. There are multiple approaches to this, but I found the following to be somewhat simple:

private subscriptions = new Subscription();

All the calls to subscribe return such a Subscription object that you can use to unsubscribe when needed. In this case, the ngOnInit implementation becomes this:

ngOnInit(): void {
  const sub = this.dataService.sharedData$.pipe(
    filter(data => !!data)
  ).subscribe(data => {
    alert(this.dataServce.sharedData);
  });
  this.subscriptions.add(sub);
}

And you also need a ngOnDestroy to unsubscribe:

ngOnDestroy() {
  this.subscriptions.unsubscribe();
}

CodePudding user response:

Try this data.service.ts

import { Injectable } from '@angular/core';
 @Injectable({
  providedIn: 'root'
  })
export class DataService {

private sharedData = new BehaviorSubject<any>(null);

   constructor() { }

   setData(data: any) : void {
      this.sharedData.next(data);
   }

  getData(): Observable<any> {
     return this.sharedData.asObservable();
  }
}

Do this in the component that is passing the data

constructor(private http:HttpClient,private dataService:DataService)
{
    this.http.post("backendURL",quote)
      .subscribe(s => {
          this.dataService.setData(s);
         });
}

Do this on the component that is receiving the data:

ngOnInit(): void {
  this.dataServce.getData().subscribe(data => {
     alert(data);
  });

}
  • Related