I\'m new to Angular and I\'m having an issue.
I\'m creating an app with several sibling components. When I update a value in one component other components don\'t u
Here's how to solve your problem using a behavior subject:
@Injectable()
export class CoachService {
apiURL = environment.apiURL;
constructor(private http: HttpClient) { }
updateProfile(info, token, us_id): Observable<any> {
return Observable.create((behaviorSubject: BehaviorSubject<any>) => {
const requestData = {
token: token,
us_id: us_id,
us_lang: info.us_lang,
us_firstname: info.us_firstname,
us_lastname: info.us_lastname,
us_sex: info.us_sex,
us_birthdate: info.us_birthdate,
us_national_number: info.us_national_number,
us_email: info.us_email,
us_gsm: info.us_gsm,
online_profile: info.online_profile,
us_address: info.us_address,
us_zip: info.us_zip,
us_city: info.us_city,
country: {
id: info.country.id
}
};
const url = [this.apiURL, '/coach/update_profile'].join('');
return this.http.post(url, requestData).subscribe(
data => {
behaviorSubject.next(data);
},
err => {
behaviorSubject.error(err);
if (err && err.status === 401) {
// Do some err handling
}
}
);
});
}
}
Now when you want to post data and subscribe to the result of your Behavior Subject from, say to the in the component you have here, you simply:
updateCoordonees() {
this.coachService.updateProfile(this.infos_profile, this.token, this.us_id)
.subscribe((data: any) => {
if (data.success && data.msg != null) {
// do something on success
}
},
(err) => {
// do some err handling
});
}
First create a BehaviourSubject
this._source = new BehaviourSubject<yourType>(initialValue);
this.source = this._source.asObservable();
Define a function to "update" the BehaviourSubject
updateSource(newValue) {
this._source.next(newValue)
}
Now subscribe in your components to the source
this.service.source.subscribe();
Note the behaviourSubject always needs an initial value and emits the last one
DOCS: https://www.learnrxjs.io/subjects/behaviorsubject.html
If you want to share the data from a httpRequest you should use shareReplay() operator instead, you can subscribe to the httpRequest from different components and the request will be made once and the data will be shared
DOCS: https://www.learnrxjs.io/operators/multicasting/sharereplay.html
I'm going to show you a simple way:
@Injectable()
export class ProfileService {
private profileObs$: BehaviorSubject<Profile> = new BehaviorSubject(null);
getProfileObs(): Observable<Profile> {
return this.profileObs$.asObservable();
}
setProfileObs(profile: Profile) {
this.profileObs$.next(profile);
}
}
Now when you update something anywhere in the application, you can set that change by the ProfileService
and each subscriber is receiving the change. I recommend you subscribe in ngOnInit
.
ngOnInit() {
this.profileService.getProfileObs().subscribe(profile => this.profile = profile);
}
Never forget to unsubscribe from the observables to prevent memory leaks!
There are many ways u can do that --> Use a subscription and unsubscribe in ngOnDestroy()
or use another subject and deliver it to takeUntil like this:
unsubscribe$: Subject<boolean> = new Subject();
...
ngOnInit() {
this.profileService.getProfileObs()
.pipe(takeUntil(this.unsubscribe$)
.subscribe(profile => this.profile = profile);
}
ngOnDestroy() {
this.unsubscribe$.next(true);
this.unsubscribe$.complete();
}
There are a few ways to do that. One of them is described here.
// ReplaySubject is more flexible than BehaviorSubject, as it
// allows you to define how many past emissions should be available.
// But you can get an equivalent code with BehaviorSubject by
// coding like this:
// private _coachProfile$: BehaviorSubject<any | null> =
// new BehaviorSubject<any | null>(null);
private _coachProfile$: ReplaySubject<any> = new ReplaySubject<any>(1);
coachProfile(token :string)
{
return this.http.post<any>(this.apiURL+'/coach/profile_infos',{
token: token,
}).subscribe((profile) => this._coachProfile$.next(profile));
}
subscribeToGetCoachProfile$()
{
return this._coachProfile$.asObservable();
}
ngOnInit() {
this.coachService.subscribeToGetCoachProfile$()
.subscribe((profile) => this.coachProfile = profile);
}
Well there are other approaches you can think of, but I think this is the simpler one given the sample code you pasted on your question.
As a side note: if you do some search on stackoverflow, you'll see that this question (or similar questions) has been asked many times here. Take a look, for example in this other approach: Multiple subscriptions without recalculate common part