feat(ivy): support injection even if no injector present (#23345)
- Remove default injection value from `inject` / `directiveInject` since it is not possible to set using annotations. - Module `Injector` is stored on `LView` instead of `LInjector` data structure because it can change only at `LView` level. (More efficient) - Add `ngInjectableDef` to `IterableDiffers` so that existing tests can pass as well as enable `IterableDiffers` to be injectable without `Injector` PR Close #23345
This commit is contained in:
@ -132,10 +132,11 @@ export function renderComponent<T>(
|
||||
scheduler: opts.scheduler || requestAnimationFrame.bind(window),
|
||||
clean: CLEAN_PROMISE,
|
||||
};
|
||||
const rootView = createLView(
|
||||
const rootView: LView = createLView(
|
||||
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType),
|
||||
createTView(null, null), null, rootContext,
|
||||
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
|
||||
rootView.injector = opts.injector || null;
|
||||
|
||||
const oldView = enterView(rootView, null !);
|
||||
let elementNode: LElementNode;
|
||||
|
@ -9,7 +9,7 @@
|
||||
// We are temporarily importing the existing viewEngine_from core so we can be sure we are
|
||||
// correctly implementing its interfaces for backwards compatibility.
|
||||
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {InjectFlags, Injector} from '../di/injector';
|
||||
import {InjectFlags, Injector, inject, setCurrentInjector} from '../di/injector';
|
||||
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
||||
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
|
||||
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
|
||||
@ -125,7 +125,6 @@ export function getOrCreateNodeInjectorForNode(node: LElementNode | LContainerNo
|
||||
cbf5: parentInjector == null ? 0 : parentInjector.cbf5 | parentInjector.bf5,
|
||||
cbf6: parentInjector == null ? 0 : parentInjector.cbf6 | parentInjector.bf6,
|
||||
cbf7: parentInjector == null ? 0 : parentInjector.cbf7 | parentInjector.bf7,
|
||||
injector: null,
|
||||
templateRef: null,
|
||||
viewContainerRef: null,
|
||||
elementRef: null,
|
||||
@ -133,16 +132,6 @@ export function getOrCreateNodeInjectorForNode(node: LElementNode | LContainerNo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an injection error with the given text and token.
|
||||
*
|
||||
* @param text The text of the error
|
||||
* @param token The token associated with the error
|
||||
* @returns The error that was created
|
||||
*/
|
||||
function createInjectionError(text: string, token: any) {
|
||||
return new Error(`ElementInjector: ${text} [${stringify(token)}]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a directive public to the DI system by adding it to an injector's bloom filter.
|
||||
@ -188,14 +177,10 @@ export function diPublic(def: DirectiveDef<any>): void {
|
||||
* @param flags Injection flags (e.g. CheckParent)
|
||||
* @returns The instance found
|
||||
*/
|
||||
export function directiveInject<T>(
|
||||
token: Type<T>, notFoundValue?: undefined, flags?: InjectFlags): T;
|
||||
export function directiveInject<T>(token: Type<T>, notFoundValue: T, flags?: InjectFlags): T;
|
||||
export function directiveInject<T>(token: Type<T>, notFoundValue: null, flags?: InjectFlags): T|
|
||||
null;
|
||||
export function directiveInject<T>(
|
||||
token: Type<T>, notFoundValue?: T | null, flags = InjectFlags.Default): T|null {
|
||||
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags, notFoundValue);
|
||||
export function directiveInject<T>(token: Type<T>): T;
|
||||
export function directiveInject<T>(token: Type<T>, flags?: InjectFlags): T|null;
|
||||
export function directiveInject<T>(token: Type<T>, flags = InjectFlags.Default): T|null {
|
||||
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -344,21 +329,20 @@ function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNo
|
||||
* @param flags Injection flags (e.g. CheckParent)
|
||||
* @returns The instance found
|
||||
*/
|
||||
export function getOrCreateInjectable<T>(
|
||||
di: LInjector, token: Type<T>, flags?: InjectFlags, defaultValue?: T | null): T|null {
|
||||
export function getOrCreateInjectable<T>(di: LInjector, token: Type<T>, flags?: InjectFlags): T|
|
||||
null {
|
||||
const bloomHash = bloomHashBit(token);
|
||||
|
||||
// If the token has a bloom hash, then it is a directive that is public to the injection system
|
||||
// (diPublic). If there is no hash, fall back to the module injector.
|
||||
if (bloomHash === null) {
|
||||
const moduleInjector = di.injector;
|
||||
if (!moduleInjector) {
|
||||
if (defaultValue != null) {
|
||||
return defaultValue;
|
||||
}
|
||||
throw createInjectionError('NotFound', token);
|
||||
const moduleInjector = getPreviousOrParentNode().view.injector;
|
||||
const formerInjector = setCurrentInjector(moduleInjector);
|
||||
try {
|
||||
return inject(token, flags);
|
||||
} finally {
|
||||
setCurrentInjector(formerInjector);
|
||||
}
|
||||
moduleInjector.get(token);
|
||||
} else {
|
||||
let injector: LInjector|null = di;
|
||||
|
||||
@ -409,7 +393,7 @@ export function getOrCreateInjectable<T>(
|
||||
|
||||
// No directive was found for the given token.
|
||||
// TODO: implement optional, check-self, and check-parent.
|
||||
throw createInjectionError('Not found', token);
|
||||
throw new Error('Implement');
|
||||
}
|
||||
|
||||
function searchMatchesQueuedForCreation<T>(node: LNode, token: any): T|null {
|
||||
|
@ -301,6 +301,7 @@ export function createLView<T>(
|
||||
dynamicViewCount: 0,
|
||||
lifecycleStage: LifecycleStage.Init,
|
||||
queries: null,
|
||||
injector: currentView && currentView.injector,
|
||||
};
|
||||
|
||||
return newView;
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {ChangeDetectorRef} from '../../change_detection/change_detector_ref';
|
||||
import {Injector} from '../../di/injector';
|
||||
import {ElementRef} from '../../linker/element_ref';
|
||||
import {TemplateRef} from '../../linker/template_ref';
|
||||
import {ViewContainerRef} from '../../linker/view_container_ref';
|
||||
@ -69,8 +68,6 @@ export interface LInjector {
|
||||
cbf6: number;
|
||||
cbf7: number;
|
||||
|
||||
injector: Injector|null;
|
||||
|
||||
/** Stores the TemplateRef so subsequent injections of the TemplateRef get the same instance. */
|
||||
templateRef: TemplateRef<any>|null;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injector} from '../../di/injector';
|
||||
import {LContainer} from './container';
|
||||
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDef, PipeDefList} from './definition';
|
||||
import {LElementNode, LViewNode, TNode} from './node';
|
||||
@ -189,6 +190,11 @@ export interface LView {
|
||||
* Queries active for this view - nodes from a view are reported to those queries
|
||||
*/
|
||||
queries: LQueries|null;
|
||||
|
||||
/**
|
||||
* An optional Module Injector to be used as fall back after Element Injectors are consulted.
|
||||
*/
|
||||
injector: Injector|null;
|
||||
}
|
||||
|
||||
/** Flags associated with an LView (saved in LView.flags) */
|
||||
|
Reference in New Issue
Block a user