i'm trying to create a reusable Modal component. in a ModalService i have a Subject, and a method that that calls next() on the subject. The ModalComponent subscribes to that subject, but whenever the method in the service is being called, the next function of the observer gets triggers twice. Anyone know what causes this?
export class ModalService {
openModal = new Subject();
constructor() { }
open(cmp) {
this.openModal.next(cmp);
}
}
Modal Component:
export class ModalComponent implements OnInit {
component: ComponentRef<any>;
@ViewChild('entry', { read: ViewContainerRef }) entry: ViewContainerRef;
constructor(
private resolver: ComponentFactoryResolver,
private modalService: ModalService
) {}
ngOnInit() {
this.modalService.openModal.subscribe(cmp => {
// CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
console.log(cmp);
});
}
The most common reason for this is that you have called subscribe() multiple times. Every time it is called it adds a new message listener, even if that same listener is already registered for that event; when a message is received, every registered listener will be called with it. );
With Angular, we can use the async pipe feature. The Async pipe will allow us to let angular know what properties on our component are Observables so it can automatically subscribe and unsubscribe to our component for us.
It turns out that as the Observable is just a definition, let's remember that in a sense its something close to a function declaration, if we subscribe to it multiple times this means that each time a new HTTP request will be issued, one for each subscription.
Subscribe() is a method in Angular that connects the observer to observable events. Whenever any change is made in these observable, a code is executed and observes the results or changes using the subscribe method. Subscribe() is a method from the rxjs library, used internally by Angular.
It is not clear in your question where and how open()
method is called. Is it the open()
called twice or subscribe()
triggered twice?
But if you want to share the last value with the subscribers you could use shareReplay()
in pipe()
like this:
export class ModalService {
openModalSubject = new Subject();
openModal = this.openModalSubject.asObservable().pipe(shareReplay());
constructor() { }
open(cmp) {
this.openModalSubject.next(cmp);
}
}
UPDATE
And in your modal component, you need to unsubscribe
from the observable when navigating from it. You can do it two ways.
First Way:
modalSubscription: Subscription;
ngOnInit() {
this.modalSubscription = this.modalService.openModal.subscribe(cmp => {
// CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
console.log(cmp);
});
}
ngOnDestroy(){
this.modalSubscription.unsubscribe();
}
Second Way:
unsubscribeSignal: Subject<void> = new Subject();
ngOnInit() {
this.modalSubscription = this.modalService.openModal
.pipe(
takeUntil(this.unsubscribeSignal.asObservable()),
)
.subscribe(cmp => {
// CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
console.log(cmp);
});
}
ngOnDestroy(){
this.unsubscribeSignal.next();
}
I prefer the second way mostly. This way, you can unsubscribe more than one observable at once.
The best way is to push all subscriptions in the array and unsubscribe it into the ngondestroy.
First import the Subscription from rxjs
import { Subscription} from 'rxjs';
second create global property in component
subscriptions: Subscription[] = [];
Third push all the subscribe in subscriptions property
constructor(){
this.subscriptions.push(this.Service.subject1.subscribe((result) => {
console.log('subject1');
}));
this.subscriptions.push(this.dataService.subject2.subscribe((data) => {
console.log('subject2')
}
Lastly unsubscribe it
ngOnDestroy() {
this.subscriptions.forEach(sub => sub.unsubscribe());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With