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);
});
}