I'm not sure of the small details here, so maybe this isn't even supposed to work—but it seems like there should be some solution to this. I have a parent component that uses two child components in tabs, like so:
<div class="container" *ngIf="page === 'tab1'">
<refresher-component></refresher-component>
<child-component1></child-component1>
</div>
<div class="container" *ngIf="page === 'tab2'">
<refresher-component></refresher-component>
<child-component2></child-component2>
</div>
The parent also has a refresher component, that is responsible for refreshing the data in both of the tabs. Each of the child components injects a service that implements the Refreshable interface:
constructor(private service1: Service1)
constructor(private service2: Service2)
Each service looks like this (replace 1 with 2 for 2nd service):
@Injectable()
export class Service1 implements Refreshable<Type1[]>
The refersher-component
looks like this:
public constructor(@Inject(RefresherServiceToken) public refreshableService: Refreshable<any>) {
console.log('refreshable', this.refreshableService);
}
What happens is that when I load the page (1st tab is default), the console.log
outputs Service1. However, when changing to Tab 2, the constructor is called again, but it also outputs Service1. Therefore the refresh is also done on Service1's data, and does not affect Service2.
Is this normal behavior, because the route doesn't change, and do I need to add something to reset the service? Is there a simple way to troubleshoot this behavior in general? (Angular 8)
It looks like what was missing from my troubleshooting was the provider of the RefresherServiceToken. This must exist somewhere. In my case the provided was given in an "empty" module that was the parent of the parent component, and since the refresher-component
is outside of the children, it also can't be overridden at the child-component
level.
There are three solutions for this that I can think of:
Simplest:
Move the refresher-component
inside each child-component
. In my actual code it was a bit difficult, but in the above example it's trivial. After that, add the necessary provider on the child component level, for example:
providers: [
{provide: RefresherServiceToken, useExisting: Service2}
]
In this case, even if there was a provider on the parent level, it is overridden.
Simple to implement, difficult to read/follow later
Configure the provider dynamically at the parent-component
level. There are a few ways to do it, as described here:
How to add providers to Injector dynamically?
Potentially the most difficult to implement, but simplest to grasp
Change the way these pages are built, in that the two child components should be in two completely separate pages/routes, whereas the shared template parts (say, header/footer) are in shared components. This completely works around the problem, because there is no one parent for both child components, and therefore they cannot have the same provider. Naturally separate providers need to be defined for each of them, as outlined in the first example.