I have an angular service as shown below:
@Injectable({ providedIn: 'root' })
export class SelectItemGroupsResourceFacade {
$assetPath = signal<string>('')
$appName = signal<string>('')
#selectItemGroupsResource: ResourceRef<TSelectItemGroup[] | undefined> =
resource<TSelectItemGroup[], TSelectItemGroupsLoaderRequest>({
request: () => ({
appName: this.$appName(),
assetPath: this.$assetPath()
}),
loader: selectItemGroupsLoader()
})
configureResource = (
appName: string,
assetPath: string
): ResourceRef<TSelectItemGroup[] | undefined> => {
this.$appName.set(appName)
this.$assetPath.set(assetPath)
return this.#selectItemGroupsResource
}
}
The issue is that when the two calls below are made, the last one wins.
#resrcFacade = inject(SelectItemGroupsResourceFacade)
$titlesResrc: ResourceRef<TSelectItemGroup[] | undefined> =
this.#resrcFacade.configureResource('registration', 'titles.json')
$suffixResrc: ResourceRef<TSelectItemGroup[] | undefined> =
this.#resrcFacade.configureResource('registration', 'suffixes.json')
What I actually need is two different instances of SelectItemGroupsResourceFacade, instead of a single one. Using the providers decorator would give the same result in the same component
The answer to your question is to use InjectionToken
to provide the same class, but with different instance.
We define the injection tokens:
export const titlesToken = new InjectionToken('titlesToken');
export const suffixesToken = new InjectionToken('suffixesToken');
Then these tokens are served as separate providers:
@Component({
selector: 'app-root',
template: `
{{$titlesResrc.value()}} | {{$suffixResrc.value()}}
`,
providers: [
{ provide: titlesToken, useClass: SelectItemGroupsResourceFacade },
{ provide: suffixesToken, useClass: SelectItemGroupsResourceFacade },
],
})
We then get these providers using these tokens:
export class App {
#titlesResrcFacade = inject<SelectItemGroupsResourceFacade>(titlesToken);
$titlesResrc: ResourceRef<any[] | undefined> =
this.#titlesResrcFacade.configureResource('registration', 'titles.json');
#suffixesResrcFacade = inject<SelectItemGroupsResourceFacade>(suffixesToken);
$suffixResrc: ResourceRef<any[] | undefined> =
this.#suffixesResrcFacade.configureResource(
'registration',
'suffixes.json'
);
}
import {
Component,
Injectable,
signal,
ResourceRef,
resource,
ResourceLoader,
InjectionToken,
inject,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
@Injectable({ providedIn: 'root' })
export class SelectItemGroupsResourceFacade {
$assetPath = signal<string>('');
$appName = signal<string>('');
selectItemGroupsLoader(): ResourceLoader<any, any> {
return () => Promise.resolve(Math.random());
}
#selectItemGroupsResource: ResourceRef<any[] | undefined> = resource<
any[],
any
>({
request: () => ({
appName: this.$appName(),
assetPath: this.$assetPath(),
}),
loader: this.selectItemGroupsLoader(),
});
configureResource = (
appName: string,
assetPath: string
): ResourceRef<any[] | undefined> => {
this.$appName.set(appName);
this.$assetPath.set(assetPath);
return this.#selectItemGroupsResource;
};
}
export const titlesToken = new InjectionToken('titlesToken');
export const suffixesToken = new InjectionToken('suffixesToken');
@Component({
selector: 'app-root',
template: `
{{$titlesResrc.value()}} | {{$suffixResrc.value()}}
`,
providers: [
{ provide: titlesToken, useClass: SelectItemGroupsResourceFacade },
{ provide: suffixesToken, useClass: SelectItemGroupsResourceFacade },
],
})
export class App {
#titlesResrcFacade = inject<SelectItemGroupsResourceFacade>(titlesToken);
$titlesResrc: ResourceRef<any[] | undefined> =
this.#titlesResrcFacade.configureResource('registration', 'titles.json');
#suffixesResrcFacade = inject<SelectItemGroupsResourceFacade>(suffixesToken);
$suffixResrc: ResourceRef<any[] | undefined> =
this.#suffixesResrcFacade.configureResource(
'registration',
'suffixes.json'
);
}
bootstrapApplication(App);