I have an application with lazy loaded modules.
In one specific lazy loaded module, I have a parent component, which has router-outlet
.
In that parent component I have a button which basically emit an event using a shared service (provided on the lazy loaded module).
each child component (which is loaded in router-outlet
) is subscribing to that event using the same shared service!
I tried to recreate my use case in the following plunkr using heroes demo.
Open Dev tools to see console
messages.
Heroes
Link (it should be selected by default).Admin
Link.Emit Test
button (upper right nav)You'll see -in the console- that Event was received by both components, even both components should not be 'Active' !!!
1) Is this by design?
2) How to know if the current Component is the active one?
From my understanding, EventEmitter/Subject can be subscribed as many times, but when unsubscribed you cannot use it/subscribe to it AFAIK.
My solution was:
1) in service I ended doing the folowing:
get(){
if (!this.testEvent.closed) {
this.testEvent.complete();
this.testEvent.unsubscribe();
}
this.testEvent= new EventEmitter<void>();
return this.testEvent;
}
}
2) In each component I subscribe to the event, I added ngDestroy and unsubscribed the event:
ngOnDestroy() {
this.testEvent.unsubscribe();
}
ActivatedRoutelink. Provides access to information about a route associated with a component that is loaded in an outlet.
Router outlet is a dynamic component that the router uses to display in this case either the Home or the AllLessons components.
Router-Outlet is an Angular directive from the router library that is used to insert the component matched by routes to be displayed on the screen.
You have a service, which is a singleton. This service exists from the beginning of the application until its end.
You have two components. These are not singletons. They are created when they must be displayed on a page, and destroyed when they must not be anymore.
And, when the components are created, you subscribe to an observable inside the singleton service. What does it mean? It means that the observable needs to keep a reference to your observer, which itself has an emplicit reference (this) to the component instance. Without that reference, the observable wouldn't be able to call the observer when an event is emitted. So, even though Angular doesn't need your component instance anymore, the observable still has a reference to it, and calls it when an event is emitted.
You thus need to unsubscribe when the component is not needed anymore:
private subscription: Subscription;
ngOnInit() {
this.subscription = this.service.getTestEvent().subscribe(...);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
Without doing that, not only do you have observers called for nothing, making the app slower, but you also have a memory leak.
The point is that you never unsubscribe the event.
The more you click your users the more you will see lines in the console.
Any time you click you subscribe to the event, i.e. you add a callback that will get executed any time the event is raised, unless you unsubscribe.
In the method ngOnDestroy()
you should call the unsubscribe()
method on the subscription (which is the object returned by the subscribe()
method).
In other words something like this
subscrition: Subscription;
ngOnInit() {
this.subscription = this.service.getTestEvent().subscribe( (e) => {
console.log('HeroListComponent ==>');
});
.....
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
I hope this helps.
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