From 9c99e6a8380668cc0e14985ef2dea6cb05daa0b6 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Mon, 22 Jan 2018 17:43:52 -0800 Subject: [PATCH] refactor(ivy): move init hooks into TView (#21650) PR Close #21650 --- packages/core/src/render3/component.ts | 5 +- packages/core/src/render3/hooks.ts | 153 ++++++++++++++++++ packages/core/src/render3/index.ts | 7 +- packages/core/src/render3/instructions.ts | 159 ++++--------------- packages/core/src/render3/interfaces/view.ts | 34 +++- packages/core/test/render3/di_spec.ts | 4 +- packages/core/test/render3/lifecycle_spec.ts | 65 ++++---- 7 files changed, 259 insertions(+), 168 deletions(-) create mode 100644 packages/core/src/render3/hooks.ts diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index d9eaaafd5e..a63fa40961 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -13,8 +13,7 @@ import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_facto import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref'; import {assertNotNull} from './assert'; - -import {NG_HOST_SYMBOL, createError, createLView, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions'; +import {NG_HOST_SYMBOL, createError, createLView, createTView, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions'; import {ComponentDef, ComponentType} from './interfaces/definition'; import {LElementNode} from './interfaces/node'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; @@ -173,7 +172,7 @@ export function renderComponent( const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag); const oldView = enterView( createLView( - -1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), {data: []}), + -1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), createTView()), null !); try { // Create element node at index 0 in data array diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts new file mode 100644 index 0000000000..15590d7243 --- /dev/null +++ b/packages/core/src/render3/hooks.ts @@ -0,0 +1,153 @@ + +import {LifecycleHooksMap} from './interfaces/definition'; +import {LNodeFlags} from './interfaces/node'; +import {HookData, LView, TView} from './interfaces/view'; + + +/** + * Enum used by the lifecycle (l) instruction to determine which lifecycle hook is requesting + * processing. + */ +export const enum LifecycleHook { + ON_INIT = 0b00, + ON_CHECK = 0b01, + ON_CHANGES = 0b10 +} + +/** Constants used by lifecycle hooks to determine when and how a hook should be called. */ +export const enum LifecycleHookUtils { + /* Mask used to get the type of the lifecycle hook from flags in hook queue */ + TYPE_MASK = 0b00000000000000000000000000000001, + + /* Shift needed to get directive index from flags in hook queue */ + INDX_SHIFT = 1 +} + +/** + * Loops through the directives on a node and queues their afterContentInit, + * afterContentChecked, and onDestroy hooks, if they exist. + */ +export function queueLifecycleHooks(flags: number, currentView: LView): void { + // It's necessary to loop through the directives at elementEnd() (rather than storing + // the hooks at creation time) so we can preserve the current hook order. All hooks + // for projected components and directives must be called *before* their hosts. + const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; + const start = flags >> LNodeFlags.INDX_SHIFT; + let contentHooks = currentView.contentHooks; + let cleanup = currentView.cleanup; + + for (let i = start, end = start + size; i < end; i++) { + const instance = currentView.data[i]; + if (instance.ngAfterContentInit != null) { + (contentHooks || (currentView.contentHooks = contentHooks = [ + ])).push(LifecycleHook.ON_INIT, instance.ngAfterContentInit, instance); + } + if (instance.ngAfterContentChecked != null) { + (contentHooks || (currentView.contentHooks = contentHooks = [ + ])).push(LifecycleHook.ON_CHECK, instance.ngAfterContentChecked, instance); + } + if (instance.ngOnDestroy != null) { + (cleanup || (currentView.cleanup = cleanup = [])).push(instance.ngOnDestroy, instance); + } + } +} + +/** + * If this is the first template pass, any ngOnInit or ngDoCheck hooks on the current directive + * will be queued on TView.initHooks. + * + * The directive index and hook type are encoded into one number (1st bit: type, remaining bits: + * directive index), then saved in the even indices of the initHooks array. The odd indices + * hold the hook functions themselves. + * + * @param index The index of the directive in LView.data + * @param hooks The static hooks map on the directive def + * @param tView The current TView + */ +export function queueInitHooks(index: number, hooks: LifecycleHooksMap, tView: TView): void { + if (tView.firstTemplatePass && hooks.onInit != null) { + const hookFlags = index << LifecycleHookUtils.INDX_SHIFT; + (tView.initHooks || (tView.initHooks = [])).push(hookFlags, hooks.onInit); + } + + if (tView.firstTemplatePass && hooks.doCheck != null) { + const hookFlags = (index << LifecycleHookUtils.INDX_SHIFT) | LifecycleHook.ON_CHECK; + (tView.initHooks || (tView.initHooks = [])).push(hookFlags, hooks.doCheck); + } +} + +/** + * Calls onInit and doCheck calls if they haven't already been called. + * + * @param currentView The current view + * @param initHooks The init hooks for this view + */ +export function executeInitHooks(currentView: LView): void { + const initHooks = currentView.tView.initHooks; + + if (currentView.initHooksCalled === false && initHooks != null) { + const data = currentView.data; + const creationMode = currentView.creationMode; + + for (let i = 0; i < initHooks.length; i += 2) { + const flags = initHooks[i] as number; + const hook = initHooks[i | 1] as() => void; + const onInit = (flags & LifecycleHookUtils.TYPE_MASK) === LifecycleHook.ON_INIT; + const instance = data[flags >> LifecycleHookUtils.INDX_SHIFT]; + if (onInit === false || creationMode) { + hook.call(instance); + } + } + currentView.initHooksCalled = true; + } +} + +/** Iterates over view hook functions and calls them. */ +export function executeViewHooks(data: any[], viewHookStartIndex: number | null): void { + if (viewHookStartIndex == null) return; + executeHooksAndRemoveInits(data, viewHookStartIndex); +} + +/** + * Calls all afterContentInit and afterContentChecked hooks for the view, then splices + * out afterContentInit hooks to prep for the next run in update mode. + */ +export function executeContentHooks(currentView: LView): void { + if (currentView.contentHooks != null && currentView.contentHooksCalled === false) { + executeHooksAndRemoveInits(currentView.contentHooks, 0); + currentView.contentHooksCalled = true; + } +} + +/** + * Calls lifecycle hooks with their contexts, then splices out any init-only hooks + * to prep for the next run in update mode. + * + * @param arr The array in which the hooks are found + * @param startIndex The index at which to start calling hooks + */ +function executeHooksAndRemoveInits(arr: any[], startIndex: number): void { + // Instead of using splice to remove init hooks after their first run (expensive), we + // shift over the AFTER_CHECKED hooks as we call them and truncate once at the end. + let checkIndex = startIndex; + let writeIndex = startIndex; + while (checkIndex < arr.length) { + // Call lifecycle hook with its context + arr[checkIndex + 1].call(arr[checkIndex + 2]); + + if (arr[checkIndex] === LifecycleHook.ON_CHECK) { + // We know if the writeIndex falls behind that there is an init that needs to + // be overwritten. + if (writeIndex < checkIndex) { + arr[writeIndex] = arr[checkIndex]; + arr[writeIndex + 1] = arr[checkIndex + 1]; + arr[writeIndex + 2] = arr[checkIndex + 2]; + } + writeIndex += 3; + } + checkIndex += 3; + } + + // Truncate once at the writeIndex + arr.length = writeIndex; +} diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 73aa3c5e77..6cd9ec6593 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -24,8 +24,6 @@ export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_REA // clang-format off export { - LifecycleHook, - NO_CHANGE as NC, bind as b, @@ -68,10 +66,13 @@ export { export { QueryList, - + query as Q, queryRefresh as qR, } from './query'; + +export {LifecycleHook} from './hooks'; + // clang-format on export { diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 81d5daebd9..639a07f312 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -27,20 +27,9 @@ import {isNodeMatchingSelector} from './node_selector_matcher'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType} from './interfaces/definition'; import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer'; import {isDifferent, stringify} from './util'; +import {LifecycleHook, executeViewHooks, executeContentHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks'; -/** - * Enum used by the lifecycle (l) instruction to determine which lifecycle hook is requesting - * processing. - */ -export const enum LifecycleHook { - ON_INIT = 1, - ON_DESTROY = 2, - ON_CHANGES = 4, - AFTER_INIT = 8, - AFTER_CHECKED = 16 -} - /** * Directive (D) sets a property on all component instances using this constant as a key and the * component's host node (LElement) as the value. This is used in methods like detectChanges to @@ -91,7 +80,7 @@ let tData: TData; /** State of the current view being processed. */ let currentView: LView; // The initialization has to be after the `let`, otherwise `createLView` can't see `let`. -currentView = createLView(null !, null !, {data: []}); +currentView = createLView(null !, null !, createTView()); let currentQuery: LQuery|null; @@ -129,19 +118,6 @@ let bindingIndex: number; */ let cleanup: any[]|null; -/** - * Array of ngAfterContentInit and ngAfterContentChecked hooks. - * - * These need to be queued so they can be called all at once after init hooks - * and any embedded views are finished processing (to maintain backwards-compatible - * order). - * - * 1st index is: type of hook (afterContentInit or afterContentChecked) - * 2nd index is: method to call - * 3rd index is: context - */ -let contentHooks: any[]|null; - /** Index in the data array at which view hooks begin to be stored. */ let viewHookStartIndex: number|null; @@ -166,7 +142,6 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null) viewHookStartIndex = newView.viewHookStartIndex; cleanup = newView.cleanup; - contentHooks = newView.contentHooks; renderer = newView.renderer; if (host != null) { @@ -183,8 +158,10 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null) * the direction of traversal (up or down the view tree) a bit clearer. */ export function leaveView(newView: LView): void { - executeViewHooks(); + executeViewHooks(data, viewHookStartIndex); + currentView.initHooksCalled = false; currentView.contentHooksCalled = false; + if (currentView.tView.firstTemplatePass) currentView.tView.firstTemplatePass = false; enterView(newView, null); } @@ -209,7 +186,8 @@ export function createLView( template: template, context: context, dynamicViewCount: 0, - contentHooksCalled: false + contentHooksCalled: false, + initHooksCalled: false }; return newView; @@ -508,7 +486,11 @@ function hack_findQueryName( * @returns TView */ function getOrCreateTView(template: ComponentTemplate): TView { - return template.ngPrivateData || (template.ngPrivateData = { data: [] } as never); + return template.ngPrivateData || (template.ngPrivateData = createTView() as never); +} + +export function createTView(): TView { + return {data: [], firstTemplatePass: true, initHooks: null}; } function setUpAttributes(native: RElement, attrs: string[]): void { @@ -627,35 +609,7 @@ export function elementEnd() { ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Element); const query = previousOrParentNode.query; query && query.addNode(previousOrParentNode); - queueLifecycleHooks(); -} - -/** - * Loops through the directives on a node and queues their afterContentInit, - * afterContentChecked, and onDestroy hooks, if they exist. - */ -function queueLifecycleHooks(): void { - // It's necessary to loop through the directives at elementEnd() (rather than storing - // the hooks at creation time) so we can preserve the current hook order. All hooks - // for projected components and directives must be called *before* their hosts. - const flags = previousOrParentNode.flags; - const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; - const start = flags >> LNodeFlags.INDX_SHIFT; - - for (let i = start, end = start + size; i < end; i++) { - const instance = data[i]; - if (instance.ngAfterContentInit != null) { - (contentHooks || (currentView.contentHooks = contentHooks = [ - ])).push(LifecycleHook.AFTER_INIT, instance.ngAfterContentInit, instance); - } - if (instance.ngAfterContentChecked != null) { - (contentHooks || (currentView.contentHooks = contentHooks = [ - ])).push(LifecycleHook.AFTER_CHECKED, instance.ngAfterContentChecked, instance); - } - if (instance.ngOnDestroy != null) { - (cleanup || (currentView.cleanup = cleanup = [])).push(instance.ngOnDestroy, instance); - } - } + queueLifecycleHooks(previousOrParentNode.flags, currentView); } /** @@ -949,6 +903,11 @@ export function directiveCreate( if (tNode && tNode.attrs) { setInputsFromAttrs(instance, directiveDef !.inputs, tNode); } + + // Init hooks are queued now so ngOnInit is called in host components before + // any projected components. + queueInitHooks(index, directiveDef.lifecycleHooks, currentView.tView); + return instance; } @@ -1013,31 +972,13 @@ function generateInitialInputs( * Accepts a lifecycle hook type and determines when and how the related lifecycle hook * callback should run. * - * For the onInit lifecycle hook, it will return whether or not the ngOnInit() function - * should run. If so, ngOnInit() will be called outside of this function. - * - * e.g. l(LifecycleHook.ON_INIT) && ctx.ngOnInit(); - * - * For the onDestroy lifecycle hook, this instruction also accepts an onDestroy - * method that should be stored and called internally when the parent view is being - * cleaned up. - * - * e.g. l(LifecycleHook.ON_DESTROY, ctx, ctx.onDestroy); - * * @param lifecycle * @param self * @param method */ -export function lifecycle(lifecycle: LifecycleHook.AFTER_INIT, self: any, method: Function): void; -export function lifecycle( - lifecycle: LifecycleHook.AFTER_CHECKED, self: any, method: Function): void; -export function lifecycle(lifecycle: LifecycleHook): boolean; -export function lifecycle(lifecycle: LifecycleHook, self?: any, method?: Function): boolean { - if (lifecycle === LifecycleHook.ON_INIT) { - return creationMode; - } else if ( - creationMode && - (lifecycle === LifecycleHook.AFTER_INIT || lifecycle === LifecycleHook.AFTER_CHECKED)) { +export function lifecycle(lifecycle: LifecycleHook, self: any, method: Function): boolean { + if (creationMode && + (lifecycle === LifecycleHook.ON_INIT || lifecycle === LifecycleHook.ON_CHECK)) { if (viewHookStartIndex == null) { currentView.viewHookStartIndex = viewHookStartIndex = data.length; } @@ -1046,12 +987,6 @@ export function lifecycle(lifecycle: LifecycleHook, self?: any, method?: Functio return false; } -/** Iterates over view hook functions and calls them. */ -export function executeViewHooks(): void { - if (viewHookStartIndex == null) return; - executeHooksAndRemoveInits(data, viewHookStartIndex); -} - ////////////////////////// //// ViewContainer & View @@ -1124,6 +1059,10 @@ export function containerRefreshStart(index: number): void { ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container); isParent = true; (previousOrParentNode as LContainerNode).data.nextIndex = 0; + + // We need to execute init hooks here so ngOnInit hooks are called in top level views + // before they are called in embedded views (for backwards compatibility). + executeInitHooks(currentView); } /** @@ -1210,7 +1149,7 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV ngDevMode && assertNodeType(parent, LNodeFlags.Container); const tContainer = (parent !.tNode as TContainerNode).data; if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) { - tContainer[viewIndex] = { data: [] } as TView; + tContainer[viewIndex] = createTView(); } return tContainer[viewIndex]; } @@ -1261,7 +1200,8 @@ export const componentRefresh: ngDevMode && assertDataInRange(directiveIndex); const hostView = element.data !; ngDevMode && assertNotEqual(hostView, null, 'hostView'); - executeContentHooks(); + executeInitHooks(currentView); + executeContentHooks(currentView); const directive = data[directiveIndex]; const oldView = enterView(hostView, element); try { @@ -1273,49 +1213,6 @@ export const componentRefresh: } }; -/** - * Calls all afterContentInit and afterContentChecked hooks for the view, then splices - * out afterContentInit hooks to prep for the next run in update mode. - */ -function executeContentHooks(): void { - if (contentHooks == null || currentView.contentHooksCalled) return; - executeHooksAndRemoveInits(contentHooks, 0); - currentView.contentHooksCalled = true; -} - -/** - * Calls lifecycle hooks with their contexts, then splices out any init-only hooks - * to prep for the next run in update mode. - * - * @param arr The array in which the hooks are found - * @param startIndex The index at which to start calling hooks - */ -function executeHooksAndRemoveInits(arr: any[], startIndex: number): void { - // Instead of using splice to remove init hooks after their first run (expensive), we - // shift over the AFTER_CHECKED hooks as we call them and truncate once at the end. - let checkIndex = startIndex; - let writeIndex = startIndex; - while (checkIndex < arr.length) { - // Call lifecycle hook with its context - arr[checkIndex + 1].call(arr[checkIndex + 2]); - - if (arr[checkIndex] === LifecycleHook.AFTER_CHECKED) { - // We know if the writeIndex falls behind that there is an init that needs to - // be overwritten. - if (writeIndex < checkIndex) { - arr[writeIndex] = arr[checkIndex]; - arr[writeIndex + 1] = arr[checkIndex + 1]; - arr[writeIndex + 2] = arr[checkIndex + 2]; - } - writeIndex += 3; - } - checkIndex += 3; - } - - // Truncate once at the writeIndex - arr.length = writeIndex; -} - /** * Instruction to distribute projectable nodes among occurrences in a given template. * It takes all the selectors from the entire component's template and decides where diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index f6137e1aef..8dd09dd476 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -103,6 +103,16 @@ export interface LView { */ contentHooks: any[]|null; + /** + * Whether or not the ngOnInit and ngDoCheck hooks have been called in this change + * detection run. + * + * These two hooks are executed by the first Comp.r() instruction that runs OR the + * first cR instruction that runs (so inits are run for the top level view before + * any embedded views). For this reason, the call must be tracked. + */ + initHooksCalled: boolean; + /** * Whether or not the content hooks have been called in this change detection run. * @@ -194,7 +204,29 @@ export interface LViewOrLContainer { * * Stored on the template function as ngPrivateData. */ -export interface TView { data: TData; } +export interface TView { + /** Static data equivalent of LView.data[]. Contains TNodes and directive defs. */ + data: TData; + + /** Whether or not this template has been processed. */ + firstTemplatePass: boolean; + + /** + * Array of init hooks that should be executed for this view. + * + * Even indices: Flags (1st bit: hook type, remaining: directive index) + * Odd indices: Hook function + */ + initHooks: HookData|null; +} + +/** + * Array of init hooks that should be executed for a view. + * + * Even indices: Flags (1st bit: hook type, remaining: directive index) + * Odd indices: Hook function + */ +export type HookData = (number | (() => void))[]; /** * Static data that corresponds to the instance-specific data array on an LView. diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index cee83523f1..0b1f83a5bb 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -11,7 +11,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; import {defineComponent} from '../../src/render3/definition'; import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector} from '../../src/render3/di'; import {C, E, PublicFeature, T, V, b, b2, cR, cr, defineDirective, e, inject, injectElementRef, injectTemplateRef, injectViewContainerRef, m, t, v} from '../../src/render3/index'; -import {createLNode, createLView, enterView, leaveView} from '../../src/render3/instructions'; +import {createLNode, createLView, createTView, enterView, leaveView} from '../../src/render3/instructions'; import {LInjector} from '../../src/render3/interfaces/injector'; import {LNodeFlags} from '../../src/render3/interfaces/node'; @@ -312,7 +312,7 @@ describe('di', () => { describe('getOrCreateNodeInjector', () => { it('should handle initial undefined state', () => { - const contentView = createLView(-1, null !, {data: []}); + const contentView = createLView(-1, null !, createTView()); const oldView = enterView(contentView, null !); try { const parent = createLNode(0, LNodeFlags.Element, null, null); diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 6384a949b0..e688beaef2 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {C, ComponentDef, ComponentTemplate, E, L, LifecycleHook, T, V, b, cR, cr, defineComponent, e, l, m, p, r, v, pD, P} from '../../src/render3/index'; +import {C, ComponentDef, ComponentTemplate, E, L, LifecycleHook, P, T, V, b, cR, cr, defineComponent, defineDirective, e, l, m, p, pD, r, v} from '../../src/render3/index'; + import {containerEl, renderToHtml} from './render_util'; describe('lifecycles', () => { @@ -52,8 +53,6 @@ describe('lifecycles', () => { type: Component, tag: name, factory: () => new Component(), - hostBindings: function(directiveIndex: number, elementIndex: number): - void { l(LifecycleHook.ON_INIT) && m(directiveIndex).ngOnInit(); }, inputs: {val: 'val'}, template }); }; @@ -220,6 +219,30 @@ describe('lifecycles', () => { expect(events).toEqual(['comp1', 'projected1', 'comp2', 'projected2']); }); + it('should be called on directives after component', () => { + class Directive { + ngOnInit() { events.push('dir'); } + + static ngDirectiveDef = defineDirective({type: Directive, factory: () => new Directive()}); + } + + function Template(ctx: any, cm: boolean) { + if (cm) { + E(0, Comp, null, [Directive]); + e(); + } + Comp.ngComponentDef.h(1, 0); + Comp.ngComponentDef.r(1, 0); + } + + renderToHtml(Template, {}); + expect(events).toEqual(['comp', 'dir']); + + renderToHtml(Template, {}); + expect(events).toEqual(['comp', 'dir']); + + }); + it('should call onInit properly in for loop', () => { /** * @@ -334,22 +357,13 @@ describe('lifecycles', () => { return class Component { ngDoCheck() { events.push(name); - allEvents.push('ngDoCheck ' + name); + allEvents.push('check ' + name); } - ngOnInit() { allEvents.push('ngOnInit ' + name); } + ngOnInit() { allEvents.push('init ' + name); } - static ngComponentDef = defineComponent({ - type: Component, - tag: name, - factory: () => new Component(), - hostBindings: function( - this: ComponentDef, directiveIndex: number, elementIndex: number): void { - l(LifecycleHook.ON_INIT) && m(directiveIndex).ngOnInit(); - m(directiveIndex).ngDoCheck(); - }, - template - }); + static ngComponentDef = + defineComponent({type: Component, tag: name, factory: () => new Component(), template}); }; } @@ -402,10 +416,10 @@ describe('lifecycles', () => { } renderToHtml(Template, {}); - expect(allEvents).toEqual(['ngOnInit comp', 'ngDoCheck comp']); + expect(allEvents).toEqual(['init comp', 'check comp']); renderToHtml(Template, {}); - expect(allEvents).toEqual(['ngOnInit comp', 'ngDoCheck comp', 'ngDoCheck comp']); + expect(allEvents).toEqual(['init comp', 'check comp', 'check comp']); }); }); @@ -829,8 +843,8 @@ describe('lifecycles', () => { refresh: (directiveIndex: number, elementIndex: number) => { r(directiveIndex, elementIndex, template); const comp = m(directiveIndex) as Component; - l(LifecycleHook.AFTER_INIT, comp, comp.ngAfterViewInit); - l(LifecycleHook.AFTER_CHECKED, comp, comp.ngAfterViewChecked); + l(LifecycleHook.ON_INIT, comp, comp.ngAfterViewInit); + l(LifecycleHook.ON_CHECK, comp, comp.ngAfterViewChecked); }, inputs: {val: 'val'}, template: template @@ -1693,16 +1707,11 @@ describe('lifecycles', () => { type: Component, tag: name, factory: () => new Component(), - hostBindings: function(directiveIndex: number, elementIndex: number): void { - const comp = D(directiveIndex) as Component; - l(LifecycleHook.ON_INIT) && comp.ngOnInit(); - comp.ngDoCheck(); - }, refresh: function(directiveIndex: number, elementIndex: number): void { r(directiveIndex, elementIndex, template); - const comp = D(directiveIndex) as Component; - l(LifecycleHook.AFTER_INIT, comp, comp.ngAfterViewInit); - l(LifecycleHook.AFTER_CHECKED, comp, comp.ngAfterViewChecked); + const comp = m(directiveIndex) as Component; + l(LifecycleHook.ON_INIT, comp, comp.ngAfterViewInit); + l(LifecycleHook.ON_CHECK, comp, comp.ngAfterViewChecked); }, inputs: {val: 'val'}, template });