@@ -64,30 +64,36 @@ type SanitizerFn = (value: any) => string;
64
64
* bindings, refreshes child components.
65
65
* Note: view hooks are triggered later when leaving the view.
66
66
*/
67
- function refreshDescendantViews ( viewData : LViewData ) {
67
+ export function refreshDescendantViews ( viewData : LViewData , rf : RenderFlags | null ) {
68
68
const tView = getTView ( ) ;
69
- const creationMode = getCreationMode ( ) ;
70
- const checkNoChangesMode = getCheckNoChangesMode ( ) ;
71
- setHostBindings ( tView , viewData ) ;
72
69
const parentFirstTemplatePass = getFirstTemplatePass ( ) ;
73
70
74
71
// This needs to be set before children are processed to support recursive components
75
72
tView . firstTemplatePass = false ;
76
73
setFirstTemplatePass ( false ) ;
77
74
78
- if ( ! checkNoChangesMode ) {
79
- executeInitHooks ( viewData , tView , creationMode ) ;
80
- }
81
- refreshDynamicEmbeddedViews ( viewData ) ;
75
+ // Dynamically created views must run first only in creation mode. If this is a
76
+ // creation-only pass, we should not call lifecycle hooks or evaluate bindings.
77
+ // This will be done in the update-only pass.
78
+ if ( rf !== RenderFlags . Create ) {
79
+ const creationMode = getCreationMode ( ) ;
80
+ const checkNoChangesMode = getCheckNoChangesMode ( ) ;
81
+ setHostBindings ( tView , viewData ) ;
82
+
83
+ if ( ! checkNoChangesMode ) {
84
+ executeInitHooks ( viewData , tView , creationMode ) ;
85
+ }
86
+ refreshDynamicEmbeddedViews ( viewData ) ;
82
87
83
- // Content query results must be refreshed before content hooks are called.
84
- refreshContentQueries ( tView ) ;
88
+ // Content query results must be refreshed before content hooks are called.
89
+ refreshContentQueries ( tView ) ;
85
90
86
- if ( ! checkNoChangesMode ) {
87
- executeHooks ( viewData , tView . contentHooks , tView . contentCheckHooks , creationMode ) ;
91
+ if ( ! checkNoChangesMode ) {
92
+ executeHooks ( viewData , tView . contentHooks , tView . contentCheckHooks , creationMode ) ;
93
+ }
88
94
}
89
95
90
- refreshChildComponents ( tView . components , parentFirstTemplatePass ) ;
96
+ refreshChildComponents ( tView . components , parentFirstTemplatePass , rf ) ;
91
97
}
92
98
93
99
@@ -144,23 +150,14 @@ function refreshContentQueries(tView: TView): void {
144
150
145
151
/** Refreshes child components in the current view. */
146
152
function refreshChildComponents (
147
- components : number [ ] | null , parentFirstTemplatePass : boolean ) : void {
153
+ components : number [ ] | null , parentFirstTemplatePass : boolean , rf : RenderFlags | null ) : void {
148
154
if ( components != null ) {
149
155
for ( let i = 0 ; i < components . length ; i ++ ) {
150
- componentRefresh ( components [ i ] , parentFirstTemplatePass ) ;
156
+ componentRefresh ( components [ i ] , parentFirstTemplatePass , rf ) ;
151
157
}
152
158
}
153
159
}
154
160
155
- export function executeInitAndContentHooks ( viewData : LViewData ) : void {
156
- if ( ! getCheckNoChangesMode ( ) ) {
157
- const tView = getTView ( ) ;
158
- const creationMode = getCreationMode ( ) ;
159
- executeInitHooks ( viewData , tView , creationMode ) ;
160
- executeHooks ( viewData , tView . contentHooks , tView . contentCheckHooks , creationMode ) ;
161
- }
162
- }
163
-
164
161
export function createLViewData < T > (
165
162
renderer : Renderer3 , tView : TView , context : T | null , flags : LViewFlags ,
166
163
sanitizer ?: Sanitizer | null ) : LViewData {
@@ -304,7 +301,7 @@ export function renderTemplate<T>(
304
301
createLViewData ( renderer , componentTView , context , LViewFlags . CheckAlways , sanitizer ) ;
305
302
hostView [ HOST_NODE ] = createNodeAtIndex ( 0 , TNodeType . Element , hostNode , null , null ) ;
306
303
}
307
- renderComponentOrTemplate ( hostView , context , templateFn ) ;
304
+ renderComponentOrTemplate ( hostView , context , null , templateFn ) ;
308
305
309
306
return hostView ;
310
307
}
@@ -369,7 +366,7 @@ export function renderEmbeddedTemplate<T>(
369
366
namespaceHTML ( ) ;
370
367
tView . template ! ( rf , context ) ;
371
368
if ( rf & RenderFlags . Update ) {
372
- refreshDescendantViews ( viewToRender ) ;
369
+ refreshDescendantViews ( viewToRender , null ) ;
373
370
} else {
374
371
// This must be set to false immediately after the first creation run because in an
375
372
// ngFor loop, all the views will be created together before update mode runs and turns
@@ -404,7 +401,8 @@ export function nextContext<T = any>(level: number = 1): T {
404
401
}
405
402
406
403
function renderComponentOrTemplate < T > (
407
- hostView : LViewData , componentOrContext : T , templateFn ?: ComponentTemplate < T > ) {
404
+ hostView : LViewData , componentOrContext : T , rf : RenderFlags | null ,
405
+ templateFn ?: ComponentTemplate < T > ) {
408
406
const rendererFactory = getRendererFactory ( ) ;
409
407
const oldView = enterView ( hostView , hostView [ HOST_NODE ] ) ;
410
408
try {
@@ -413,17 +411,9 @@ function renderComponentOrTemplate<T>(
413
411
}
414
412
if ( templateFn ) {
415
413
namespaceHTML ( ) ;
416
- templateFn ( getRenderFlags ( hostView ) , componentOrContext ! ) ;
417
- refreshDescendantViews ( hostView ) ;
418
- } else {
419
- executeInitAndContentHooks ( hostView ) ;
420
-
421
- // Element was stored at 0 in data and directive was stored at 0 in directives
422
- // in renderComponent()
423
- setHostBindings ( getTView ( ) , hostView ) ;
424
- refreshDynamicEmbeddedViews ( hostView ) ;
425
- componentRefresh ( HEADER_OFFSET , false ) ;
414
+ templateFn ( rf || getRenderFlags ( hostView ) , componentOrContext ! ) ;
426
415
}
416
+ refreshDescendantViews ( hostView , rf ) ;
427
417
} finally {
428
418
if ( rendererFactory . end ) {
429
419
rendererFactory . end ( ) ;
@@ -1488,7 +1478,7 @@ function findDirectiveMatches(tView: TView, viewData: LViewData, tNode: TNode):
1488
1478
}
1489
1479
1490
1480
/** Stores index of component's host element so it will be queued for view refresh during CD. */
1491
- function queueComponentIndexForCheck ( previousOrParentTNode : TNode ) : void {
1481
+ export function queueComponentIndexForCheck ( previousOrParentTNode : TNode ) : void {
1492
1482
ngDevMode &&
1493
1483
assertEqual ( getFirstTemplatePass ( ) , true , 'Should only be called in first template pass.' ) ;
1494
1484
const tView = getTView ( ) ;
@@ -1829,7 +1819,7 @@ export function containerRefreshEnd(): void {
1829
1819
* Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes them
1830
1820
* by executing an associated template function.
1831
1821
*/
1832
- export function refreshDynamicEmbeddedViews ( lViewData : LViewData ) {
1822
+ function refreshDynamicEmbeddedViews ( lViewData : LViewData ) {
1833
1823
for ( let current = getLViewChild ( lViewData ) ; current !== null ; current = current [ NEXT ] ) {
1834
1824
// Note: current can be an LViewData or an LContainer instance, but here we are only interested
1835
1825
// in LContainer. We can tell it's an LContainer because its length is less than the LViewData
@@ -1957,7 +1947,7 @@ function getOrCreateEmbeddedTView(
1957
1947
export function embeddedViewEnd ( ) : void {
1958
1948
const viewData = getViewData ( ) ;
1959
1949
const viewHost = viewData [ HOST_NODE ] ;
1960
- refreshDescendantViews ( viewData ) ;
1950
+ refreshDescendantViews ( viewData , null ) ;
1961
1951
leaveView ( viewData [ PARENT ] ! ) ;
1962
1952
setPreviousOrParentTNode ( viewHost ! ) ;
1963
1953
setIsParent ( false ) ;
@@ -1971,15 +1961,15 @@ export function embeddedViewEnd(): void {
1971
1961
* @param adjustedElementIndex Element index in LViewData[] (adjusted for HEADER_OFFSET)
1972
1962
*/
1973
1963
export function componentRefresh < T > (
1974
- adjustedElementIndex : number , parentFirstTemplatePass : boolean ) : void {
1964
+ adjustedElementIndex : number , parentFirstTemplatePass : boolean , rf : RenderFlags | null ) : void {
1975
1965
ngDevMode && assertDataInRange ( adjustedElementIndex ) ;
1976
1966
const hostView = getComponentViewByIndex ( adjustedElementIndex , getViewData ( ) ) ;
1977
1967
ngDevMode && assertNodeType ( getTView ( ) . data [ adjustedElementIndex ] as TNode , TNodeType . Element ) ;
1978
1968
1979
1969
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
1980
1970
if ( viewAttached ( hostView ) && hostView [ FLAGS ] & ( LViewFlags . CheckAlways | LViewFlags . Dirty ) ) {
1981
1971
parentFirstTemplatePass && syncViewWithBlueprint ( hostView ) ;
1982
- detectChangesInternal ( hostView , hostView [ CONTEXT ] ) ;
1972
+ detectChangesInternal ( hostView , hostView [ CONTEXT ] , rf ) ;
1983
1973
}
1984
1974
}
1985
1975
@@ -2261,7 +2251,8 @@ export function tick<T>(component: T): void {
2261
2251
function tickRootContext ( rootContext : RootContext ) {
2262
2252
for ( let i = 0 ; i < rootContext . components . length ; i ++ ) {
2263
2253
const rootComponent = rootContext . components [ i ] ;
2264
- renderComponentOrTemplate ( readPatchedLViewData ( rootComponent ) ! , rootComponent ) ;
2254
+ renderComponentOrTemplate (
2255
+ readPatchedLViewData ( rootComponent ) ! , rootComponent , RenderFlags . Update ) ;
2265
2256
}
2266
2257
}
2267
2258
@@ -2279,7 +2270,7 @@ function tickRootContext(rootContext: RootContext) {
2279
2270
* @param component The component which the change detection should be performed on.
2280
2271
*/
2281
2272
export function detectChanges < T > ( component : T ) : void {
2282
- detectChangesInternal ( getComponentViewByInstance ( component ) ! , component ) ;
2273
+ detectChangesInternal ( getComponentViewByInstance ( component ) ! , component , null ) ;
2283
2274
}
2284
2275
2285
2276
/**
@@ -2326,32 +2317,35 @@ export function checkNoChangesInRootView(lViewData: LViewData): void {
2326
2317
}
2327
2318
2328
2319
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
2329
- export function detectChangesInternal < T > ( hostView : LViewData , component : T ) {
2320
+ function detectChangesInternal < T > ( hostView : LViewData , component : T , rf : RenderFlags | null ) {
2330
2321
const hostTView = hostView [ TVIEW ] ;
2331
2322
const oldView = enterView ( hostView , hostView [ HOST_NODE ] ) ;
2332
2323
const templateFn = hostTView . template ! ;
2333
2324
const viewQuery = hostTView . viewQuery ;
2334
2325
2335
2326
try {
2336
2327
namespaceHTML ( ) ;
2337
- createViewQuery ( viewQuery , hostView [ FLAGS ] , component ) ;
2338
- templateFn ( getRenderFlags ( hostView ) , component ) ;
2339
- refreshDescendantViews ( hostView ) ;
2340
- updateViewQuery ( viewQuery , component ) ;
2328
+ createViewQuery ( viewQuery , rf , hostView [ FLAGS ] , component ) ;
2329
+ templateFn ( rf || getRenderFlags ( hostView ) , component ) ;
2330
+ refreshDescendantViews ( hostView , rf ) ;
2331
+ updateViewQuery ( viewQuery , hostView [ FLAGS ] , component ) ;
2341
2332
} finally {
2342
- leaveView ( oldView ) ;
2333
+ leaveView ( oldView , rf === RenderFlags . Create ) ;
2343
2334
}
2344
2335
}
2345
2336
2346
2337
function createViewQuery < T > (
2347
- viewQuery : ComponentQuery < { } > | null , flags : LViewFlags , component : T ) : void {
2348
- if ( viewQuery && ( flags & LViewFlags . CreationMode ) ) {
2338
+ viewQuery : ComponentQuery < { } > | null , renderFlags : RenderFlags | null , viewFlags : LViewFlags ,
2339
+ component : T ) : void {
2340
+ if ( viewQuery && ( renderFlags === RenderFlags . Create ||
2341
+ ( renderFlags === null && ( viewFlags & LViewFlags . CreationMode ) ) ) ) {
2349
2342
viewQuery ( RenderFlags . Create , component ) ;
2350
2343
}
2351
2344
}
2352
2345
2353
- function updateViewQuery < T > ( viewQuery : ComponentQuery < { } > | null , component : T ) : void {
2354
- if ( viewQuery ) {
2346
+ function updateViewQuery < T > (
2347
+ viewQuery : ComponentQuery < { } > | null , flags : LViewFlags , component : T ) : void {
2348
+ if ( viewQuery && flags & RenderFlags . Update ) {
2355
2349
viewQuery ( RenderFlags . Update , component ) ;
2356
2350
}
2357
2351
}
0 commit comments