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', () => { | ||||
|  | ||||
							
								
								
									
										2
									
								
								tools/public_api_guard/core/core.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								tools/public_api_guard/core/core.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user