fix(core): support `Attribute` DI decorator in `deps` section of a token (#37085)

This commit fixes a bug when `Attribute` DI decorator is used in the
`deps` section of a token that uses a factory function. The problem
appeared because the `Attribute` DI decorator was not handled correctly
while injecting factory function attributes.

Closes #36479

PR Close #37085
This commit is contained in:
Sonu Kapoor 2020-05-13 06:25:47 -04:00 committed by Andrew Kushnir
parent a965589eb8
commit f5cbf0bb54
4 changed files with 112 additions and 4 deletions

View File

@ -176,6 +176,57 @@
"packages/core/src/change_detection/differs/default_keyvalue_differ.ts",
"packages/core/src/change_detection/differs/keyvalue_differs.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts",
"packages/core/src/di/jit/environment.ts",
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/injector.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts",
"packages/core/src/di/jit/environment.ts",
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts",
"packages/core/src/di/jit/util.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/reflective_injector.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/reflective_injector.ts",
"packages/core/src/di/reflective_provider.ts",
"packages/core/src/di/metadata.ts",
"packages/core/src/render3/instructions/di.ts"
],
[
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts"
@ -184,6 +235,16 @@
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/injector.ts"
],
[
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/injector.ts",
"packages/core/src/di/null_injector.ts"
],
[
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/injector.ts",
"packages/core/src/di/r3_injector.ts"
],
[
"packages/core/src/di/injector_token.ts",
"packages/core/src/di/injector.ts"

View File

@ -25,6 +25,7 @@ export {
SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__,
} from './di/injectable';
export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector';
export {CREATE_ATTRIBUTE_DECORATOR__POST_R3__ as ɵCREATE_ATTRIBUTE_DECORATOR__POST_R3__} from './di/metadata';
export {
NG_INJ_DEF as ɵNG_INJ_DEF,
NG_PROV_DEF as ɵNG_PROV_DEF,

View File

@ -7,7 +7,7 @@
*/
import {makeParamDecorator} from '../util/decorators';
import {ɵɵinjectAttribute} from '../render3/instructions/di';
/**
@ -274,11 +274,25 @@ export interface Attribute {
attributeName: string;
}
function CREATE_ATTRIBUTE_DECORATOR__PRE_R3__(): AttributeDecorator {
return makeParamDecorator(
'Attribute',
(attributeName?: string) => ({attributeName}));
}
export function CREATE_ATTRIBUTE_DECORATOR__POST_R3__(): AttributeDecorator {
return makeParamDecorator(
'Attribute',
(attributeName?: string) =>
({attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName!)}));
}
const CREATE_ATTRIBUTE_DECORATOR_IMPL = CREATE_ATTRIBUTE_DECORATOR__PRE_R3__;
/**
* Attribute decorator and metadata.
*
* @Annotation
* @publicApi
*/
export const Attribute: AttributeDecorator =
makeParamDecorator('Attribute', (attributeName?: string) => ({attributeName}));
*/
export const Attribute: AttributeDecorator = CREATE_ATTRIBUTE_DECORATOR_IMPL();

View File

@ -2771,6 +2771,38 @@ describe('di', () => {
});
});
describe('attribute tokens', () => {
it('should be able to provide an attribute token', () => {
const TOKEN = new InjectionToken<string>('Some token');
function factory(token: string): string {
return token + ' with factory';
}
@Component({
selector: 'my-comp',
template: '...',
providers: [{
provide: TOKEN,
deps: [[new Attribute('token')]],
useFactory: factory,
}]
})
class MyComp {
constructor(@Inject(TOKEN) readonly token: string) {}
}
@Component({template: `<my-comp token='token'></my-comp>`})
class WrapperComp {
@ViewChild(MyComp) myComp!: MyComp;
}
TestBed.configureTestingModule({declarations: [MyComp, WrapperComp]});
const fixture = TestBed.createComponent(WrapperComp);
fixture.detectChanges();
expect(fixture.componentInstance.myComp.token).toBe('token with factory');
});
});
it('should not cause cyclic dependency if same token is requested in deps with @SkipSelf', () => {
@Component({
selector: 'my-comp',