refactor(ivy): move LView.template and component templates to TView (#24300)

PR Close #24300
This commit is contained in:
Kara Erickson 2018-06-04 13:07:09 -07:00 committed by Victor Berchet
parent d814eaad95
commit 57eacf4b5a
5 changed files with 39 additions and 46 deletions

View File

@ -139,7 +139,7 @@ export function renderComponent<T>(
}; };
const rootView: LView = createLView( const rootView: LView = createLView(
rendererFactory.createRenderer(hostNode, componentDef.rendererType), rendererFactory.createRenderer(hostNode, componentDef.rendererType),
createTView(-1, null, null), null, rootContext, createTView(-1, null, null, null), rootContext,
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways); componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView.injector = opts.injector || null; rootView.injector = opts.injector || null;
@ -160,7 +160,7 @@ export function renderComponent<T>(
executeInitAndContentHooks(); executeInitAndContentHooks();
setHostBindings(ROOT_DIRECTIVE_INDICES); setHostBindings(ROOT_DIRECTIVE_INDICES);
detectChangesInternal(elementNode.data as LView, elementNode, componentDef, component); detectChangesInternal(elementNode.data as LView, elementNode, component);
} finally { } finally {
leaveView(oldView); leaveView(oldView);
if (rendererFactory.end) rendererFactory.end(); if (rendererFactory.end) rendererFactory.end();

View File

@ -704,12 +704,12 @@ export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef
const hostTNode = hostNode.tNode; const hostTNode = hostNode.tNode;
const hostTView = hostNode.view.tView; const hostTView = hostNode.view.tView;
if (!hostTNode.tViews) { if (!hostTNode.tViews) {
hostTNode.tViews = createTView(-1, hostTView.directiveRegistry, hostTView.pipeRegistry); hostTNode.tViews = createTView(
-1, hostNode.data.template !, hostTView.directiveRegistry, hostTView.pipeRegistry);
} }
ngDevMode && assertNotNull(hostTNode.tViews, 'TView must be allocated'); ngDevMode && assertNotNull(hostTNode.tViews, 'TView must be allocated');
di.templateRef = new TemplateRef<any>( di.templateRef = new TemplateRef<any>(
getOrCreateElementRef(di), hostTNode.tViews as TView, hostNode.data.template !, getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(), hostNode.data.queries);
getRenderer(), hostNode.data.queries);
} }
return di.templateRef; return di.templateRef;
} }
@ -718,15 +718,14 @@ class TemplateRef<T> implements viewEngine_TemplateRef<T> {
readonly elementRef: viewEngine_ElementRef; readonly elementRef: viewEngine_ElementRef;
constructor( constructor(
elementRef: viewEngine_ElementRef, private _tView: TView, elementRef: viewEngine_ElementRef, private _tView: TView, private _renderer: Renderer3,
private _template: ComponentTemplate<T>, private _renderer: Renderer3,
private _queries: LQueries|null) { private _queries: LQueries|null) {
this.elementRef = elementRef; this.elementRef = elementRef;
} }
createEmbeddedView(context: T): viewEngine_EmbeddedViewRef<T> { createEmbeddedView(context: T): viewEngine_EmbeddedViewRef<T> {
const viewNode = renderEmbeddedTemplate( const viewNode =
null, this._tView, this._template, context, this._renderer, this._queries); renderEmbeddedTemplate(null, this._tView, context, this._renderer, this._queries);
return new EmbeddedViewRef(viewNode, this._template, context); return new EmbeddedViewRef(viewNode, this._tView.template !as ComponentTemplate<T>, context);
} }
} }

View File

@ -303,8 +303,8 @@ export function executeInitAndContentHooks(): void {
} }
export function createLView<T>( export function createLView<T>(
renderer: Renderer3, tView: TView, template: ComponentTemplate<T>| null, context: T | null, renderer: Renderer3, tView: TView, context: T | null, flags: LViewFlags,
flags: LViewFlags, sanitizer?: Sanitizer | null): LView { sanitizer?: Sanitizer | null): LView {
const newView = { const newView = {
parent: currentView, parent: currentView,
flags: flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit, flags: flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit,
@ -317,7 +317,6 @@ export function createLView<T>(
tail: null, tail: null,
next: null, next: null,
bindingIndex: -1, bindingIndex: -1,
template: template,
context: context, context: context,
queries: null, queries: null,
injector: currentView && currentView.injector, injector: currentView && currentView.injector,
@ -469,8 +468,8 @@ export function renderTemplate<T>(
host = createLNode( host = createLNode(
-1, TNodeType.Element, hostNode, null, null, -1, TNodeType.Element, hostNode, null, null,
createLView( createLView(
providedRendererFactory.createRenderer(null, null), tView, null, {}, providedRendererFactory.createRenderer(null, null), tView, {}, LViewFlags.CheckAlways,
LViewFlags.CheckAlways, sanitizer)); sanitizer));
} }
const hostView = host.data !; const hostView = host.data !;
ngDevMode && assertNotNull(hostView, 'Host node should have an LView defined in host.data.'); ngDevMode && assertNotNull(hostView, 'Host node should have an LView defined in host.data.');
@ -489,8 +488,8 @@ export function renderTemplate<T>(
* TView for dynamically created views on their host TNode, which only has one instance. * TView for dynamically created views on their host TNode, which only has one instance.
*/ */
export function renderEmbeddedTemplate<T>( export function renderEmbeddedTemplate<T>(
viewNode: LViewNode | null, tView: TView, template: ComponentTemplate<T>, context: T, viewNode: LViewNode | null, tView: TView, context: T, renderer: Renderer3,
renderer: Renderer3, queries?: LQueries | null): LViewNode { queries?: LQueries | null): LViewNode {
const _isParent = isParent; const _isParent = isParent;
const _previousOrParentNode = previousOrParentNode; const _previousOrParentNode = previousOrParentNode;
let oldView: LView; let oldView: LView;
@ -500,8 +499,8 @@ export function renderEmbeddedTemplate<T>(
previousOrParentNode = null !; previousOrParentNode = null !;
if (viewNode == null) { if (viewNode == null) {
const lView = createLView( const lView =
renderer, tView, template, context, LViewFlags.CheckAlways, getCurrentSanitizer()); createLView(renderer, tView, context, LViewFlags.CheckAlways, getCurrentSanitizer());
if (queries) { if (queries) {
lView.queries = queries.createView(); lView.queries = queries.createView();
@ -511,7 +510,7 @@ export function renderEmbeddedTemplate<T>(
rf = RenderFlags.Create; rf = RenderFlags.Create;
} }
oldView = enterView(viewNode.data, viewNode); oldView = enterView(viewNode.data, viewNode);
template(rf, context); tView.template !(rf, context);
if (rf & RenderFlags.Update) { if (rf & RenderFlags.Update) {
refreshView(); refreshView();
} else { } else {
@ -788,7 +787,7 @@ function getOrCreateTView(
// and not on embedded templates. // and not on embedded templates.
return template.ngPrivateData || return template.ngPrivateData ||
(template.ngPrivateData = createTView(-1, directives, pipes) as never); (template.ngPrivateData = createTView(-1, template, directives, pipes) as never);
} }
/** /**
@ -799,11 +798,12 @@ function getOrCreateTView(
* @param pipes Registry of pipes for this view * @param pipes Registry of pipes for this view
*/ */
export function createTView( export function createTView(
viewIndex: number, directives: DirectiveDefListOrFactory | null, viewIndex: number, template: ComponentTemplate<any>| null,
pipes: PipeDefListOrFactory | null): TView { directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView {
ngDevMode && ngDevMode.tView++; ngDevMode && ngDevMode.tView++;
return { return {
id: viewIndex, id: viewIndex,
template: template,
node: null !, node: null !,
data: [], data: [],
childIndex: -1, // Children set in addToViewTree(), if any childIndex: -1, // Children set in addToViewTree(), if any
@ -887,7 +887,7 @@ export function hostElement(
const node = createLNode( const node = createLNode(
0, TNodeType.Element, rNode, null, null, 0, TNodeType.Element, rNode, null, null,
createLView( createLView(
renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null, renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer)); def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
if (firstTemplatePass) { if (firstTemplatePass) {
@ -1337,7 +1337,7 @@ function addComponentLogic<T>(index: number, instance: T, def: ComponentDef<T>):
currentView, previousOrParentNode.tNode.index as number, currentView, previousOrParentNode.tNode.index as number,
createLView( createLView(
rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType), rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType),
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
getCurrentSanitizer())); getCurrentSanitizer()));
// We need to set the host node/data here because when the component LNode was created, // We need to set the host node/data here because when the component LNode was created,
@ -1592,8 +1592,7 @@ function refreshDynamicChildren() {
// The directives and pipes are not needed here as an existing view is only being refreshed. // The directives and pipes are not needed here as an existing view is only being refreshed.
const dynamicView = lViewNode.data; const dynamicView = lViewNode.data;
ngDevMode && assertNotNull(dynamicView.tView, 'TView must be allocated'); ngDevMode && assertNotNull(dynamicView.tView, 'TView must be allocated');
renderEmbeddedTemplate( renderEmbeddedTemplate(lViewNode, dynamicView.tView, dynamicView.context !, renderer);
lViewNode, dynamicView.tView, dynamicView.template !, dynamicView.context !, renderer);
} }
} }
} }
@ -1653,8 +1652,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
} else { } else {
// When we create a new LView, we always reset the state of the instructions. // When we create a new LView, we always reset the state of the instructions.
const newView = createLView( const newView = createLView(
renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, null, renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, LViewFlags.CheckAlways,
LViewFlags.CheckAlways, getCurrentSanitizer()); getCurrentSanitizer());
if (lContainer.queries) { if (lContainer.queries) {
newView.queries = lContainer.queries.createView(); newView.queries = lContainer.queries.createView();
@ -1685,7 +1684,7 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV
if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) {
const tView = currentView.tView; const tView = currentView.tView;
containerTViews[viewIndex] = containerTViews[viewIndex] =
createTView(viewIndex, tView.directiveRegistry, tView.pipeRegistry); createTView(viewIndex, null, tView.directiveRegistry, tView.pipeRegistry);
} }
return containerTViews[viewIndex]; return containerTViews[viewIndex];
} }
@ -1760,10 +1759,7 @@ export function componentRefresh<T>(directiveIndex: number, elementIndex: number
// Only attached CheckAlways components or attached, dirty OnPush components should be checked // Only attached CheckAlways components or attached, dirty OnPush components should be checked
if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
ngDevMode && assertDataInRange(directiveIndex, directives !); ngDevMode && assertDataInRange(directiveIndex, directives !);
const def = currentView.tView.directives ![directiveIndex] as ComponentDef<T>; detectChangesInternal(hostView, element, getDirectiveInstance(directives ![directiveIndex]));
detectChangesInternal(
hostView, element, def, getDirectiveInstance(directives ![directiveIndex]));
} }
} }
@ -2078,9 +2074,7 @@ export function getRootView(component: any): LView {
export function detectChanges<T>(component: T): void { export function detectChanges<T>(component: T): void {
const hostNode = _getComponentHostLElementNode(component); const hostNode = _getComponentHostLElementNode(component);
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView'); ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
const componentIndex = hostNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift; detectChangesInternal(hostNode.data as LView, hostNode, component);
const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>;
detectChangesInternal(hostNode.data as LView, hostNode, def, component);
} }
@ -2100,10 +2094,9 @@ export function checkNoChanges<T>(component: T): void {
} }
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
export function detectChangesInternal<T>( export function detectChangesInternal<T>(hostView: LView, hostNode: LElementNode, component: T) {
hostView: LView, hostNode: LElementNode, def: ComponentDef<T>, component: T) {
const oldView = enterView(hostView, hostNode); const oldView = enterView(hostView, hostNode);
const template = def.template; const template = hostView.tView.template !;
try { try {
template(getRenderFlags(hostView), component); template(getRenderFlags(hostView), component);

View File

@ -126,11 +126,6 @@ export interface LView {
*/ */
tView: TView; tView: TView;
/**
* For dynamically inserted views, the template function to refresh the view.
*/
template: ComponentTemplate<{}>|null;
/** /**
* - For embedded views, the context with which to render the template. * - For embedded views, the context with which to render the template.
* - For root view of the root component the context contains change detection data. * - For root view of the root component the context contains change detection data.
@ -212,6 +207,12 @@ export interface TView {
*/ */
readonly id: number; readonly id: number;
/**
* The template function used to refresh the view of dynamically created views
* and components. Will be null for inline views.
*/
template: ComponentTemplate<{}>|null;
/** /**
* Pointer to the `TNode` that represents the root of the view. * Pointer to the `TNode` that represents the root of the view.
* *

View File

@ -1404,7 +1404,7 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => { describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => { it('should handle initial undefined state', () => {
const contentView = const contentView =
createLView(null !, createTView(-1, null, null), null, null, LViewFlags.CheckAlways); createLView(null !, createTView(-1, null, null, null), null, LViewFlags.CheckAlways);
const oldView = enterView(contentView, null !); const oldView = enterView(contentView, null !);
try { try {
const parent = createLNode(0, TNodeType.Element, null, null, null, null); const parent = createLNode(0, TNodeType.Element, null, null, null, null);