feat(ivy): implement the getters of ViewContainerRef (#25174)
BREAKING CHANGE: ViewContainerRef.parentInjector is deprecated without replacement PR Close #25174
This commit is contained in:
parent
e99d860393
commit
cd89eb8404
|
@ -41,6 +41,7 @@ export abstract class ViewContainerRef {
|
|||
|
||||
abstract get injector(): Injector;
|
||||
|
||||
/** @deprecated No replacement */
|
||||
abstract get parentInjector(): Injector;
|
||||
|
||||
/**
|
||||
|
|
|
@ -552,9 +552,11 @@ export const QUERY_READ_FROM_NODE =
|
|||
ngDevMode && assertNodeOfPossibleTypes(node, TNodeType.Container, TNodeType.Element);
|
||||
if (directiveIdx > -1) {
|
||||
return node.view[DIRECTIVES] ![directiveIdx];
|
||||
} else if (node.tNode.type === TNodeType.Element) {
|
||||
}
|
||||
if (node.tNode.type === TNodeType.Element) {
|
||||
return getOrCreateElementRef(injector);
|
||||
} else if (node.tNode.type === TNodeType.Container) {
|
||||
}
|
||||
if (node.tNode.type === TNodeType.Container) {
|
||||
return getOrCreateTemplateRef(injector);
|
||||
}
|
||||
throw new Error('fail');
|
||||
|
@ -600,26 +602,55 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine.ViewContainer
|
|||
|
||||
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
||||
|
||||
di.viewContainerRef = new ViewContainerRef(lContainerNode);
|
||||
di.viewContainerRef = new ViewContainerRef(lContainerNode, vcRefHost);
|
||||
}
|
||||
|
||||
return di.viewContainerRef;
|
||||
}
|
||||
|
||||
class NodeInjector implements Injector {
|
||||
constructor(private _lInjector: LInjector) {}
|
||||
|
||||
get(token: any): any {
|
||||
if (token === viewEngine.TemplateRef) {
|
||||
return getOrCreateTemplateRef(this._lInjector);
|
||||
}
|
||||
if (token === viewEngine.ViewContainerRef) {
|
||||
return getOrCreateContainerRef(this._lInjector);
|
||||
}
|
||||
if (token === viewEngine.ElementRef) {
|
||||
return getOrCreateElementRef(this._lInjector);
|
||||
}
|
||||
if (token === viewEngine_ChangeDetectorRef) {
|
||||
return getOrCreateChangeDetectorRef(this._lInjector, null);
|
||||
}
|
||||
|
||||
return getOrCreateInjectable(this._lInjector, token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A ref to a container that enables adding and removing views from that container
|
||||
* imperatively.
|
||||
*/
|
||||
class ViewContainerRef implements viewEngine.ViewContainerRef {
|
||||
private _viewRefs: viewEngine.ViewRef[] = [];
|
||||
// TODO(issue/24571): remove '!'.
|
||||
element !: viewEngine.ElementRef;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
injector !: Injector;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
parentInjector !: Injector;
|
||||
|
||||
constructor(private _lContainerNode: LContainerNode) {}
|
||||
|
||||
constructor(
|
||||
private _lContainerNode: LContainerNode, private _hostNode: LElementNode|LContainerNode) {}
|
||||
|
||||
get element(): ElementRef { return new ElementRef(this._hostNode.native); }
|
||||
|
||||
get injector(): Injector {
|
||||
return new NodeInjector(getOrCreateNodeInjectorForNode(this._hostNode));
|
||||
}
|
||||
|
||||
/** @deprecated No replacement */
|
||||
get parentInjector(): Injector {
|
||||
const parentLInjector = getParentLNode(this._hostNode).nodeInjector;
|
||||
return parentLInjector ? new NodeInjector(parentLInjector) : Injector.NULL;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
const lContainer = this._lContainerNode.data;
|
||||
|
@ -651,7 +682,7 @@ class ViewContainerRef implements viewEngine.ViewContainerRef {
|
|||
ngModuleRef?: viewEngine.NgModuleRef<any>|undefined): viewEngine.ComponentRef<C> {
|
||||
const contextInjector = injector || this.parentInjector;
|
||||
if (!ngModuleRef && contextInjector) {
|
||||
ngModuleRef = contextInjector.get(viewEngine.NgModuleRef);
|
||||
ngModuleRef = contextInjector.get(viewEngine.NgModuleRef, null);
|
||||
}
|
||||
|
||||
const componentRef =
|
||||
|
|
|
@ -336,7 +336,7 @@ export function createLViewData<T>(
|
|||
null, // directives
|
||||
null, // cleanupInstances
|
||||
context, // context
|
||||
viewData && viewData[INJECTOR], // injector
|
||||
viewData && viewData[INJECTOR] || null, // injector
|
||||
renderer, // renderer
|
||||
sanitizer || null, // sanitizer
|
||||
null, // tail
|
||||
|
|
|
@ -138,6 +138,7 @@ class ViewContainerRef_ implements ViewContainerData {
|
|||
|
||||
get injector(): Injector { return new Injector_(this._view, this._elDef); }
|
||||
|
||||
/** @deprecated No replacement */
|
||||
get parentInjector(): Injector {
|
||||
let view = this._view;
|
||||
let elDef = this._elDef.parent;
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
{
|
||||
"name": "EMPTY_RENDERER_TYPE_ID"
|
||||
},
|
||||
{
|
||||
"name": "ElementRef"
|
||||
},
|
||||
{
|
||||
"name": "ElementRef$1"
|
||||
},
|
||||
|
@ -98,6 +101,12 @@
|
|||
{
|
||||
"name": "NgModuleRef"
|
||||
},
|
||||
{
|
||||
"name": "NodeInjector"
|
||||
},
|
||||
{
|
||||
"name": "NullInjector"
|
||||
},
|
||||
{
|
||||
"name": "Optional"
|
||||
},
|
||||
|
@ -173,6 +182,9 @@
|
|||
{
|
||||
"name": "ViewContainerRef$1"
|
||||
},
|
||||
{
|
||||
"name": "ViewContainerRef$1"
|
||||
},
|
||||
{
|
||||
"name": "ViewEncapsulation$1"
|
||||
},
|
||||
|
@ -191,6 +203,9 @@
|
|||
{
|
||||
"name": "_ROOT_DIRECTIVE_INDICES"
|
||||
},
|
||||
{
|
||||
"name": "_THROW_IF_NOT_FOUND"
|
||||
},
|
||||
{
|
||||
"name": "__read"
|
||||
},
|
||||
|
@ -494,6 +509,9 @@
|
|||
{
|
||||
"name": "getCleanup"
|
||||
},
|
||||
{
|
||||
"name": "getClosestComponentAncestor"
|
||||
},
|
||||
{
|
||||
"name": "getCurrentSanitizer"
|
||||
},
|
||||
|
@ -515,12 +533,18 @@
|
|||
{
|
||||
"name": "getNextLNode"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateChangeDetectorRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateElementRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateHostChangeDetector"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateInjectable"
|
||||
},
|
||||
|
@ -617,6 +641,9 @@
|
|||
{
|
||||
"name": "invertObject"
|
||||
},
|
||||
{
|
||||
"name": "isComponent"
|
||||
},
|
||||
{
|
||||
"name": "isContextDirty"
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, ComponentFactoryResolver, Directive, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
|
||||
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
|
||||
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
|
||||
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, load, loadDirective, nextContext, projection, projectionDef, reserveSlots, text, textBinding} from '../../src/render3/instructions';
|
||||
|
@ -1035,6 +1035,66 @@ describe('ViewContainerRef', () => {
|
|||
'<p vcref=""></p><embedded-cmp-with-ngcontent>12<hr>34</embedded-cmp-with-ngcontent>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getters', () => {
|
||||
it('should work on elements', () => {
|
||||
function createTemplate() {
|
||||
elementStart(0, 'header', ['vcref', '']);
|
||||
elementEnd();
|
||||
elementStart(1, 'footer');
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
new TemplateFixture(createTemplate, undefined, [DirectiveWithVCRef]);
|
||||
|
||||
expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase())
|
||||
.toEqual('header');
|
||||
expect(
|
||||
directiveInstance !.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase())
|
||||
.toEqual('header');
|
||||
expect(() => directiveInstance !.vcref.parentInjector.get(ElementRef)).toThrow();
|
||||
});
|
||||
|
||||
it('should work on components', () => {
|
||||
const HeaderComponent =
|
||||
createComponent('header-cmp', function(rf: RenderFlags, ctx: any) {});
|
||||
|
||||
function createTemplate() {
|
||||
elementStart(0, 'header-cmp', ['vcref', '']);
|
||||
elementEnd();
|
||||
elementStart(1, 'footer');
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
new TemplateFixture(createTemplate, undefined, [HeaderComponent, DirectiveWithVCRef]);
|
||||
|
||||
expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase())
|
||||
.toEqual('header-cmp');
|
||||
expect(
|
||||
directiveInstance !.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase())
|
||||
.toEqual('header-cmp');
|
||||
expect(() => directiveInstance !.vcref.parentInjector.get(ElementRef)).toThrow();
|
||||
});
|
||||
|
||||
it('should work on containers', () => {
|
||||
function createTemplate() {
|
||||
container(0, embeddedTemplate, undefined, ['vcref', '']);
|
||||
elementStart(1, 'footer');
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
function updateTemplate() {
|
||||
containerRefreshStart(0);
|
||||
containerRefreshEnd();
|
||||
}
|
||||
|
||||
new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
|
||||
expect(directiveInstance !.vcref.element.nativeElement.textContent).toEqual('container');
|
||||
expect(directiveInstance !.vcref.injector.get(ElementRef).nativeElement.textContent)
|
||||
.toEqual('container');
|
||||
expect(() => directiveInstance !.vcref.parentInjector.get(ElementRef)).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('projection', () => {
|
||||
|
|
|
@ -922,7 +922,7 @@ export declare abstract class ViewContainerRef {
|
|||
abstract readonly element: ElementRef;
|
||||
abstract readonly injector: Injector;
|
||||
abstract readonly length: number;
|
||||
abstract readonly parentInjector: Injector;
|
||||
/** @deprecated */ abstract readonly parentInjector: Injector;
|
||||
abstract clear(): void;
|
||||
abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
|
||||
abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>;
|
||||
|
|
Loading…
Reference in New Issue