英文:
Angular 15: Appending to provided values when same token is provided in scope
问题
For example, parent scope provides the string "parent" with SOME_TOKEN, then when the child provides the same token (lets say with "child"), it appends to a list of values provided by that same token, making it ["child", "parent"]. I want this because I need to work with a library code that I can not change.
I tried the following function to provide the string but it throws Circular dependency error.
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN)
return token ? [...token, val] : val
}
}
}
Basically I want to get all the values that are provided, but angular only gives the most closest value in the default way.
I can achieve this with a service. Modules or components could append to the list in their constructor and remove the string in their ngOnDestroy, but that seems error prone.
Update
@Anton's answer works but I need to be able to use this concept with shared modules as well. For example:
@NgModule({
declarations: [SharedDirective],
imports: [],
exports: [SharedDirective],
providers: [provideToken("shared")]
})
export class SharedModule {}
@NgModule({
declarations: [SomeComponent],
imports: [SharedModule],
exports: [],
providers: [provideToken("some")]
})
export class SomeModule {}
When skipSelf is used, only "some" token is provided, and the "shared" token is ignored.
Update 2
When multi: true is used in the provider, no token is ignored but the resulting array becomes a nested array, so the injecting service/directive or etc needs to be able to work with it. So, I extended the directive from the library to flatten the array and remove duplicates in its constructor, solving my issue.
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN, {skipSelf: true, optional: true})
return token ? [...token, val] : val
},
multi: true
}
}
// constructor of the extended directive
constructor(
...,
@Optional()
@Inject(SOME_TOKEN)
providedToken: MaybeArray<string>,
...
) {
if (Array.isArray(providedToken)) {
providedToken = [...new Set(providedToken.flat(Infinity))]
}
super(..., providedToken, ...)
}
英文:
For example, parent scope provides the string "parent"
with SOME_TOKEN
, then when the child provides the same token (lets say with "child"
), it appends to a list of values provided by that same token, making it ["child", "parent"]
. I want this because I need to work with a library code that I can not change.
I tried the following function to provide the string but it throws Circular dependency error
.
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN)
return token ? [...token, val] : val
}
}
}
Basically I want to get all the values that are provided, but angular only gives the most closest value in the default way.
I can achieve this with a service. Modules or components could append to the list in their constructor and remove the string in their ngOnDestroy
, but that seems error prone.
Update
@Anton's answer works but I need to be able to use this concept with shared modules as well. For example:
@NgModule({
declarations: [SharedDirective],
imports: [],
exports: [SharedDirective],
providers: [provideToken("shared")]
})
export class SharedModule {}
@NgModule({
declarations: [SomeComponent],
imports: [SharedModule],
exports: [],
providers: [provideToken("some")]
})
export class SomeModule {}
When skipSelf
is used, only "some"
token is provided, and the "shared"
token is ignored.
Update 2
When multi: true
is used in the provider, no token is ignored but the resulting array becomes a nested array, so the injecting service/directive or etc needs to be able to work with it. So, I extended the directive from the library to flatten the array and remove duplicates in its constructor, solving my issue.
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN, {skipSelf: true, optional: true})
return token ? [...token, val] : val
},
multi: true
}
}
// constructor of the extended directive
constructor(
...,
@Optional()
@Inject(SOME_TOKEN)
providedToken: MaybeArray<string>,
...
) {
if (Array.isArray(providedToken)) {
providedToken = [...new Set(providedToken.flat(Infinity))]
}
super(..., providedToken, ...)
}
答案1
得分: 1
你可以尝试使用选项 skipSelf
注入令牌。它有效:
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN, { skipSelf: true })
return token ? [token, val] : val
}
}
}
英文:
You can try to inject token with option skipSelf
. It works:
export const provideToken = (val: string) => {
return {
provide: SOME_TOKEN,
useFactory: () => {
const token = inject(SOME_TOKEN, { skipSelf: true })
return token ? [token, val] : val
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论