Reputation: 53
Demo In my application I am using service to communicate between
import {Injectable} from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { TransferModel } from '../models/transfer';
@Injectable()
export class TransferService{
constructor(){}
private paramSource = new BehaviorSubject(new TransferModel());
getData = this.paramSource.asObservable();
setData(param:TransferModel) { this.paramSource.next(param)}
}
My problem is that when I go to components, it works well but in pages send other pages request also. I mean for example I am in Courses.component
constructor(private transferService:TransferService,private dataService:DataService,sessionService:SessionService,private router:Router) {
this.transferService.getData.subscribe(x=>{
this.transfer=x; if(!this.transfer.ExamId || this.transfer.ExamId<=0){ this.router.navigateByUrl("/home");return;}
this.dataService.Post(URLS.url.coursePage.getCourses,{Id:this.transfer.ExamId}).subscribe(elem=>{
this.courses=elem;
});
});
}
code above gets courses list when I click one course , below function run and
goToSubject(id){
this.transfer.CourseId=id;
this.transferService.setData(this.transfer);
this.router.navigateByUrl("/subjects");
}
goes to subjects component. In subjects component I send request with constructor.
constructor(private transferService:TransferService,private dataService:DataService,sessionService:SessionService,private router:Router) {
this.transferService.getData.subscribe(x=>{
this.transfer=x; if(!this.transfer.ExamId || this.transfer.ExamId<=0){ this.router.navigateByUrl("/home"); }
this.dataService.Post(URLS.url.subjectPage.getSubjects,{ExamId:this.transfer.ExamId,CourseId:this.transfer.CourseId}).subscribe(elem=>{
this.subjects=elem;
});
});
}
but here also another page's request call too such as in image. I need that every page send only one its request.
How can I solve this problem?
Upvotes: 2
Views: 654
Reputation: 2677
I assume since transferService.getData()
returns a Subject
, which you are subscribing, and probably not unsubscribing on component anywhere, those subscription remains alive and are invoked.onDestroy
Your goToSubject()
calls the this.transferService.setData(this.transfer);
which basically invokes all the subscriptions.
You would need to hold on the Subscription
being returned when you subscribe
and call unsubscribe()
on ngOnDestroy()
subscription: Subscription;
constructor(...){
this.subscription = this.transferService.getData.subscribe(x=>{
...
});
}
ngOnDestroy() {
if(this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
}
if you have multiple subscribe()
on your component, maybe you would like to leverage some sort of self-subscribing-implementation like takeUntil
Note: Angular HttpClient subscriptions are self-unsubscribing by default, so you don't need to call unsubscribe()
when you call httpClient.get().subscribe()
. For everything else, you would need to call unsubscribe()
.
UPDATE:
After looking at the stackblitz demo you've provided, it was confirmed that the issue was with the transferService.getData()
subject. However even with the ngOnDestroy()
unsubscribing it was still calling because you had this.transferService.setData(..)
before you redirected which basically invokes the transferService.getData().subscribe(...)
.
To fix that without major refactoring you would have to make it 'Subscribe only once' or 'automatically unsubscribe as soon as it subscribe is called'. Which brings us back to takeUntil
.
in both courses.component & subjects.component
constructor() {
const subj: Subject<boolean> = new Subject<boolean>();
this.transferService.getData
.pipe(takeUntil(subj))
.subscribe((result) => {
subj.next(true);
});
}
UPDATE 2:
Upvotes: 2