feat(core): make `new Inject()` optional for deps specified as `InjectionToken` (#14486)
fixes #10625
This commit is contained in:
parent
5f3c8441e4
commit
d6a58f9f70
|
@ -825,6 +825,8 @@ export class CompileMetadataResolver {
|
|||
token = paramEntry.attributeName;
|
||||
} else if (paramEntry instanceof Inject) {
|
||||
token = paramEntry.token;
|
||||
} else if (paramEntry instanceof InjectionToken) {
|
||||
token = paramEntry;
|
||||
} else if (isValidType(paramEntry) && token == null) {
|
||||
token = paramEntry;
|
||||
}
|
||||
|
|
|
@ -827,7 +827,6 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
function createProvider(
|
||||
token: string, {multi = false, deps = []}: {multi?: boolean, deps?: string[]} = {}):
|
||||
CompileProviderMetadata {
|
||||
const name = `provider${nextProviderId++}`;
|
||||
const compileToken = createToken(token);
|
||||
return {
|
||||
token: compileToken,
|
||||
|
|
|
@ -10,7 +10,8 @@ import {reflector} from '../reflection/reflection';
|
|||
import {Type} from '../type';
|
||||
|
||||
import {resolveForwardRef} from './forward_ref';
|
||||
import {Host, Inject, Optional, Self, SkipSelf} from './metadata';
|
||||
import {InjectionToken} from './injection_token';
|
||||
import {Inject, Optional, Self, SkipSelf} from './metadata';
|
||||
import {ClassProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ValueProvider} from './provider';
|
||||
import {invalidProviderError, mixingMultiProvidersWithRegularProvidersError, noAnnotationError} from './reflective_errors';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
|
@ -245,6 +246,8 @@ function _extractToken(
|
|||
|
||||
} else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
|
||||
visibility = paramMetadata;
|
||||
} else if (paramMetadata instanceof InjectionToken) {
|
||||
token = paramMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, Injector, Optional, Provider, ReflectiveInjector, ReflectiveKey, Self, forwardRef} from '@angular/core';
|
||||
import {Inject, Injectable, InjectionToken, Injector, Optional, Provider, ReflectiveInjector, ReflectiveKey, Self, forwardRef} from '@angular/core';
|
||||
import {ReflectiveInjector_} from '@angular/core/src/di/reflective_injector';
|
||||
import {ResolvedReflectiveProvider_} from '@angular/core/src/di/reflective_provider';
|
||||
import {getOriginalError} from '@angular/core/src/errors';
|
||||
|
@ -31,14 +31,12 @@ class TurboEngine extends Engine {}
|
|||
|
||||
@Injectable()
|
||||
class Car {
|
||||
engine: Engine;
|
||||
constructor(engine: Engine) { this.engine = engine; }
|
||||
constructor(public engine: Engine) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class CarWithOptionalEngine {
|
||||
engine: any /** TODO #9100 */;
|
||||
constructor(@Optional() engine: Engine) { this.engine = engine; }
|
||||
constructor(@Optional() public engine: Engine) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
@ -53,14 +51,11 @@ class CarWithDashboard {
|
|||
|
||||
@Injectable()
|
||||
class SportsCar extends Car {
|
||||
engine: Engine;
|
||||
constructor(engine: Engine) { super(engine); }
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class CarWithInject {
|
||||
engine: Engine;
|
||||
constructor(@Inject(TurboEngine) engine: Engine) { this.engine = engine; }
|
||||
constructor(@Inject(TurboEngine) public engine: Engine) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
@ -151,8 +146,20 @@ export function main() {
|
|||
expect(engine).toEqual('fake engine');
|
||||
});
|
||||
|
||||
it('should inject dependencies instance of InjectionToken', () => {
|
||||
const TOKEN = new InjectionToken<string>('token');
|
||||
|
||||
const injector = createInjector([
|
||||
{provide: TOKEN, useValue: 'by token'},
|
||||
{provide: Engine, useFactory: (v: string) => v, deps: [[TOKEN]]},
|
||||
]);
|
||||
|
||||
const engine = injector.get(Engine);
|
||||
expect(engine).toEqual('by token');
|
||||
});
|
||||
|
||||
it('should provide to a factory', () => {
|
||||
function sportsCarFactory(e: any /** TODO #9100 */) { return new SportsCar(e); }
|
||||
function sportsCarFactory(e: any) { return new SportsCar(e); }
|
||||
|
||||
const injector =
|
||||
createInjector([Engine, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]);
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, ElementRef, Host, Inject, Input, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core';
|
||||
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, ElementRef, Host, Inject, InjectionToken, Input, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
|
||||
|
||||
@Directive({selector: '[simpleDirective]'})
|
||||
class SimpleDirective {
|
||||
@Input('simpleDirective') value: any = null;
|
||||
|
@ -107,32 +106,27 @@ class NeedsAttribute {
|
|||
|
||||
@Directive({selector: '[needsAttributeNoType]'})
|
||||
class NeedsAttributeNoType {
|
||||
fooAttribute: any;
|
||||
constructor(@Attribute('foo') fooAttribute: any) { this.fooAttribute = fooAttribute; }
|
||||
constructor(@Attribute('foo') public fooAttribute: any) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[needsElementRef]'})
|
||||
class NeedsElementRef {
|
||||
elementRef: any;
|
||||
constructor(ref: ElementRef) { this.elementRef = ref; }
|
||||
constructor(public elementRef: ElementRef) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[needsViewContainerRef]'})
|
||||
class NeedsViewContainerRef {
|
||||
viewContainer: any;
|
||||
constructor(vc: ViewContainerRef) { this.viewContainer = vc; }
|
||||
constructor(public viewContainer: ViewContainerRef) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[needsTemplateRef]'})
|
||||
class NeedsTemplateRef {
|
||||
templateRef: any;
|
||||
constructor(ref: TemplateRef<Object>) { this.templateRef = ref; }
|
||||
constructor(public templateRef: TemplateRef<Object>) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[optionallyNeedsTemplateRef]'})
|
||||
class OptionallyNeedsTemplateRef {
|
||||
templateRef: any;
|
||||
constructor(@Optional() ref: TemplateRef<Object>) { this.templateRef = ref; }
|
||||
constructor(@Optional() public templateRef: TemplateRef<Object>) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[directiveNeedsChangeDetectorRef]'})
|
||||
|
@ -226,10 +220,17 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
|||
// On CJS fakeAsync is not supported...
|
||||
if (!getDOM().supportsDOMEvents()) return;
|
||||
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
declarations: [TestComp],
|
||||
providers: [{provide: 'appService', useValue: 'appService'}]
|
||||
}));
|
||||
const TOKEN = new InjectionToken<string>('token');
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TestComp],
|
||||
providers: [
|
||||
{provide: TOKEN, useValue: 'appService'},
|
||||
{provide: 'appService', useFactory: (v: string) => v, deps: [TOKEN]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe('injection', () => {
|
||||
it('should instantiate directives that have no dependencies', () => {
|
||||
|
|
|
@ -137,7 +137,7 @@ export function main() {
|
|||
provide: Hash,
|
||||
useFactory: (location: string) => `Hash for: ${location}`,
|
||||
// use a nested array to define metadata for dependencies.
|
||||
deps: [[new Optional(), new Inject(Location)]]
|
||||
deps: [[new Optional(), Location]]
|
||||
}]);
|
||||
|
||||
expect(injector.get(Hash)).toEqual('Hash for: null');
|
||||
|
|
Loading…
Reference in New Issue