@angular/core 16.0.0-rc.1 → 16.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/rxjs-interop/src/take_until_destroyed.mjs +3 -2
- package/esm2022/rxjs-interop/src/to_observable.mjs +19 -18
- package/esm2022/src/application_init.mjs +9 -3
- package/esm2022/src/application_ref.mjs +2 -1
- package/esm2022/src/errors.mjs +3 -3
- package/esm2022/src/hydration/annotate.mjs +5 -2
- package/esm2022/src/hydration/api.mjs +2 -2
- package/esm2022/src/hydration/error_handling.mjs +13 -5
- package/esm2022/src/hydration/node_lookup_utils.mjs +13 -8
- package/esm2022/src/hydration/tokens.mjs +3 -4
- package/esm2022/src/linker/template_ref.mjs +3 -2
- package/esm2022/src/render3/collect_native_nodes.mjs +18 -3
- package/esm2022/src/render3/component_ref.mjs +3 -2
- package/esm2022/src/render3/definition.mjs +4 -5
- package/esm2022/src/render3/i18n/i18n_parse.mjs +5 -6
- package/esm2022/src/render3/instructions/change_detection.mjs +263 -3
- package/esm2022/src/render3/instructions/element.mjs +2 -2
- package/esm2022/src/render3/instructions/element_container.mjs +2 -2
- package/esm2022/src/render3/instructions/render.mjs +125 -0
- package/esm2022/src/render3/instructions/shared.mjs +72 -427
- package/esm2022/src/render3/instructions/styling.mjs +22 -2
- package/esm2022/src/render3/instructions/template.mjs +22 -9
- package/esm2022/src/render3/interfaces/container.mjs +3 -3
- package/esm2022/src/render3/interfaces/view.mjs +2 -2
- package/esm2022/src/render3/node_manipulation.mjs +4 -8
- package/esm2022/src/render3/reactive_lview_consumer.mjs +4 -4
- package/esm2022/src/render3/reactivity/effect.mjs +8 -3
- package/esm2022/src/render3/util/view_utils.mjs +35 -11
- package/esm2022/src/render3/view_ref.mjs +2 -2
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/logger.mjs +3 -3
- package/esm2022/testing/src/test_bed.mjs +1 -3
- package/esm2022/testing/src/test_bed_common.mjs +1 -1
- package/esm2022/testing/src/test_bed_compiler.mjs +3 -8
- package/esm2022/testing/src/testing_internal.mjs +1 -2
- package/fesm2022/core.mjs +741 -640
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +23 -21
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +730 -645
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +24 -10
- package/package.json +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/guard-and-resolve-interfaces/bundle.js +13 -13
- package/schematics/migrations/remove-module-id/bundle.js +14 -14
- package/schematics/ng-generate/standalone-migration/bundle.js +965 -494
- package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
- package/testing/index.d.ts +3 -3
- package/esm2022/testing/src/ng_zone_mock.mjs +0 -34
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v16.0.0-rc.
|
|
2
|
+
* @license Angular v16.0.0-rc.3
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, provideZoneChangeDetection, Compiler, COMPILER_OPTIONS,
|
|
7
|
+
import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, provideZoneChangeDetection, Compiler, COMPILER_OPTIONS, Injector as Injector$1, ɵisEnvironmentProviders, ɵNgModuleFactory, ModuleWithComponentFactories, ɵconvertToBitFlags, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, NgZone, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
|
|
8
8
|
import { ResourceLoader } from '@angular/compiler';
|
|
9
9
|
import { Subject, Subscription } from 'rxjs';
|
|
10
10
|
|
|
@@ -840,9 +840,9 @@ function formatRuntimeError(code, message) {
|
|
|
840
840
|
// generate a link to the error details page on angular.io.
|
|
841
841
|
// We also prepend `0` to non-compile-time errors.
|
|
842
842
|
const fullCode = `NG0${Math.abs(code)}`;
|
|
843
|
-
let errorMessage = `${fullCode}${message ? ': ' + message
|
|
843
|
+
let errorMessage = `${fullCode}${message ? ': ' + message : ''}`;
|
|
844
844
|
if (ngDevMode && code < 0) {
|
|
845
|
-
const addPeriodSeparator = !errorMessage.match(/[
|
|
845
|
+
const addPeriodSeparator = !errorMessage.match(/[.,;!?\n]$/);
|
|
846
846
|
const separator = addPeriodSeparator ? '.' : '';
|
|
847
847
|
errorMessage =
|
|
848
848
|
`${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
|
|
@@ -3184,10 +3184,8 @@ function getComponentId(componentDef) {
|
|
|
3184
3184
|
if (GENERATED_COMP_IDS.has(compId)) {
|
|
3185
3185
|
const previousCompDefType = GENERATED_COMP_IDS.get(compId);
|
|
3186
3186
|
if (previousCompDefType !== componentDef.type) {
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
console.warn(`Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
|
|
3190
|
-
.selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`);
|
|
3187
|
+
console.warn(formatRuntimeError(-912 /* RuntimeErrorCode.COMPONENT_ID_COLLISION */, `Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
|
|
3188
|
+
.selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`));
|
|
3191
3189
|
}
|
|
3192
3190
|
}
|
|
3193
3191
|
else {
|
|
@@ -3205,7 +3203,7 @@ const TVIEW = 1;
|
|
|
3205
3203
|
const FLAGS = 2;
|
|
3206
3204
|
const PARENT = 3;
|
|
3207
3205
|
const NEXT = 4;
|
|
3208
|
-
const
|
|
3206
|
+
const DESCENDANT_VIEWS_TO_REFRESH = 5;
|
|
3209
3207
|
const T_HOST = 6;
|
|
3210
3208
|
const CLEANUP = 7;
|
|
3211
3209
|
const CONTEXT = 8;
|
|
@@ -3258,7 +3256,7 @@ const TYPE = 1;
|
|
|
3258
3256
|
* that the `MOVED_VIEWS` are transplanted and on-push.
|
|
3259
3257
|
*/
|
|
3260
3258
|
const HAS_TRANSPLANTED_VIEWS = 2;
|
|
3261
|
-
// PARENT, NEXT,
|
|
3259
|
+
// PARENT, NEXT, DESCENDANT_VIEWS_TO_REFRESH are indices 3, 4, and 5
|
|
3262
3260
|
// As we already have these constants in LView, we don't need to re-create them.
|
|
3263
3261
|
// T_HOST is index 6
|
|
3264
3262
|
// We already have this constants in LView, we don't need to re-create it.
|
|
@@ -4260,20 +4258,44 @@ function resetPreOrderHookFlags(lView) {
|
|
|
4260
4258
|
lView[PREORDER_HOOK_FLAGS] = 0;
|
|
4261
4259
|
}
|
|
4262
4260
|
/**
|
|
4263
|
-
*
|
|
4264
|
-
*
|
|
4261
|
+
* Adds the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
|
|
4262
|
+
* parents.
|
|
4263
|
+
*/
|
|
4264
|
+
function markViewForRefresh(lView) {
|
|
4265
|
+
if ((lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) === 0) {
|
|
4266
|
+
lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
4267
|
+
updateViewsToRefresh(lView, 1);
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
/**
|
|
4271
|
+
* Removes the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
|
|
4272
|
+
* parents.
|
|
4273
|
+
*/
|
|
4274
|
+
function clearViewRefreshFlag(lView) {
|
|
4275
|
+
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
|
|
4276
|
+
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshView */;
|
|
4277
|
+
updateViewsToRefresh(lView, -1);
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
/**
|
|
4281
|
+
* Updates the `DESCENDANT_VIEWS_TO_REFRESH` counter on the parents of the `LView` as well as the
|
|
4282
|
+
* parents above that whose
|
|
4265
4283
|
* 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
|
|
4266
4284
|
* or
|
|
4267
4285
|
* 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
|
|
4268
4286
|
*/
|
|
4269
|
-
function
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4287
|
+
function updateViewsToRefresh(lView, amount) {
|
|
4288
|
+
let parent = lView[PARENT];
|
|
4289
|
+
if (parent === null) {
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
|
|
4293
|
+
let viewOrContainer = parent;
|
|
4294
|
+
parent = parent[PARENT];
|
|
4273
4295
|
while (parent !== null &&
|
|
4274
|
-
((amount === 1 && viewOrContainer[
|
|
4275
|
-
(amount === -1 && viewOrContainer[
|
|
4276
|
-
parent[
|
|
4296
|
+
((amount === 1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 1) ||
|
|
4297
|
+
(amount === -1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 0))) {
|
|
4298
|
+
parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
|
|
4277
4299
|
viewOrContainer = parent;
|
|
4278
4300
|
parent = parent[PARENT];
|
|
4279
4301
|
}
|
|
@@ -7249,12 +7271,8 @@ function detachMovedView(declarationContainer, lView) {
|
|
|
7249
7271
|
const insertionLContainer = lView[PARENT];
|
|
7250
7272
|
ngDevMode && assertLContainer(insertionLContainer);
|
|
7251
7273
|
// If the view was marked for refresh but then detached before it was checked (where the flag
|
|
7252
|
-
// would be cleared and the counter decremented), we need to
|
|
7253
|
-
|
|
7254
|
-
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
7255
|
-
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
|
|
7256
|
-
updateTransplantedViewCount(insertionLContainer, -1);
|
|
7257
|
-
}
|
|
7274
|
+
// would be cleared and the counter decremented), we need to update the status here.
|
|
7275
|
+
clearViewRefreshFlag(lView);
|
|
7258
7276
|
movedViews.splice(declarationViewIndex, 1);
|
|
7259
7277
|
}
|
|
7260
7278
|
/**
|
|
@@ -10359,7 +10377,7 @@ class Version {
|
|
|
10359
10377
|
/**
|
|
10360
10378
|
* @publicApi
|
|
10361
10379
|
*/
|
|
10362
|
-
const VERSION = new Version('16.0.0-rc.
|
|
10380
|
+
const VERSION = new Version('16.0.0-rc.3');
|
|
10363
10381
|
|
|
10364
10382
|
// This default value is when checking the hierarchy for a token.
|
|
10365
10383
|
//
|
|
@@ -10507,12 +10525,11 @@ function isInSkipHydrationBlock(tNode) {
|
|
|
10507
10525
|
return false;
|
|
10508
10526
|
}
|
|
10509
10527
|
|
|
10510
|
-
const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
10511
10528
|
/**
|
|
10512
10529
|
* Internal token that specifies whether DOM reuse logic
|
|
10513
10530
|
* during hydration is enabled.
|
|
10514
10531
|
*/
|
|
10515
|
-
const IS_HYDRATION_DOM_REUSE_ENABLED = new InjectionToken(
|
|
10532
|
+
const IS_HYDRATION_DOM_REUSE_ENABLED = new InjectionToken((typeof ngDevMode === 'undefined' || !!ngDevMode) ? 'IS_HYDRATION_DOM_REUSE_ENABLED' : '');
|
|
10516
10533
|
// By default (in client rendering mode), we remove all the contents
|
|
10517
10534
|
// of the host element and render an application after that.
|
|
10518
10535
|
const PRESERVE_HOST_CONTENT_DEFAULT = false;
|
|
@@ -10520,7 +10537,7 @@ const PRESERVE_HOST_CONTENT_DEFAULT = false;
|
|
|
10520
10537
|
* Internal token that indicates whether host element content should be
|
|
10521
10538
|
* retained during the bootstrap.
|
|
10522
10539
|
*/
|
|
10523
|
-
const PRESERVE_HOST_CONTENT = new InjectionToken(
|
|
10540
|
+
const PRESERVE_HOST_CONTENT = new InjectionToken((typeof ngDevMode === 'undefined' || !!ngDevMode) ? 'PRESERVE_HOST_CONTENT' : '', {
|
|
10524
10541
|
providedIn: 'root',
|
|
10525
10542
|
factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
|
|
10526
10543
|
});
|
|
@@ -10630,7 +10647,6 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
|
|
|
10630
10647
|
return { propName: undefined, oldValue, newValue };
|
|
10631
10648
|
}
|
|
10632
10649
|
|
|
10633
|
-
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;
|
|
10634
10650
|
class ReactiveLViewConsumer extends ReactiveNode {
|
|
10635
10651
|
constructor() {
|
|
10636
10652
|
super(...arguments);
|
|
@@ -10638,11 +10654,12 @@ class ReactiveLViewConsumer extends ReactiveNode {
|
|
|
10638
10654
|
this._lView = null;
|
|
10639
10655
|
}
|
|
10640
10656
|
set lView(lView) {
|
|
10641
|
-
|
|
10657
|
+
(typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
10658
|
+
assertEqual(this._lView, null, 'Consumer already associated with a view.');
|
|
10642
10659
|
this._lView = lView;
|
|
10643
10660
|
}
|
|
10644
10661
|
onConsumerDependencyMayHaveChanged() {
|
|
10645
|
-
|
|
10662
|
+
(typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
10646
10663
|
assertDefined(this._lView, 'Updating a signal during template or host binding execution is not allowed.');
|
|
10647
10664
|
markViewDirty(this._lView);
|
|
10648
10665
|
}
|
|
@@ -11060,39 +11077,10 @@ function processHostBindingOpCodes(tView, lView) {
|
|
|
11060
11077
|
}
|
|
11061
11078
|
}
|
|
11062
11079
|
finally {
|
|
11063
|
-
lView[REACTIVE_HOST_BINDING_CONSUMER] === null
|
|
11080
|
+
if (lView[REACTIVE_HOST_BINDING_CONSUMER] === null) {
|
|
11064
11081
|
commitLViewConsumerIfHasProducers(lView, REACTIVE_HOST_BINDING_CONSUMER);
|
|
11065
|
-
setSelectedIndex(-1);
|
|
11066
|
-
}
|
|
11067
|
-
}
|
|
11068
|
-
/** Refreshes all content queries declared by directives in a given view */
|
|
11069
|
-
function refreshContentQueries(tView, lView) {
|
|
11070
|
-
const contentQueries = tView.contentQueries;
|
|
11071
|
-
if (contentQueries !== null) {
|
|
11072
|
-
for (let i = 0; i < contentQueries.length; i += 2) {
|
|
11073
|
-
const queryStartIdx = contentQueries[i];
|
|
11074
|
-
const directiveDefIdx = contentQueries[i + 1];
|
|
11075
|
-
if (directiveDefIdx !== -1) {
|
|
11076
|
-
const directiveDef = tView.data[directiveDefIdx];
|
|
11077
|
-
ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
|
|
11078
|
-
ngDevMode &&
|
|
11079
|
-
assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
|
|
11080
|
-
setCurrentQueryIndex(queryStartIdx);
|
|
11081
|
-
directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
|
|
11082
|
-
}
|
|
11083
11082
|
}
|
|
11084
|
-
|
|
11085
|
-
}
|
|
11086
|
-
/** Refreshes child components in the current view (update mode). */
|
|
11087
|
-
function refreshChildComponents(hostLView, components) {
|
|
11088
|
-
for (let i = 0; i < components.length; i++) {
|
|
11089
|
-
refreshComponent(hostLView, components[i]);
|
|
11090
|
-
}
|
|
11091
|
-
}
|
|
11092
|
-
/** Renders child components in the current view (creation mode). */
|
|
11093
|
-
function renderChildComponents(hostLView, components) {
|
|
11094
|
-
for (let i = 0; i < components.length; i++) {
|
|
11095
|
-
renderComponent(hostLView, components[i]);
|
|
11083
|
+
setSelectedIndex(-1);
|
|
11096
11084
|
}
|
|
11097
11085
|
}
|
|
11098
11086
|
function createLView(parentLView, tView, context, flags, host, tHostNode, environment, renderer, injector, embeddedViewInjector, hydrationInfo) {
|
|
@@ -11116,7 +11104,6 @@ function createLView(parentLView, tView, context, flags, host, tHostNode, enviro
|
|
|
11116
11104
|
lView[ID] = getUniqueLViewId();
|
|
11117
11105
|
lView[HYDRATION] = hydrationInfo;
|
|
11118
11106
|
lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
|
|
11119
|
-
lView[REACTIVE_TEMPLATE_CONSUMER] = null;
|
|
11120
11107
|
ngDevMode &&
|
|
11121
11108
|
assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
|
|
11122
11109
|
lView[DECLARATION_COMPONENT_VIEW] =
|
|
@@ -11212,195 +11199,6 @@ function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
|
|
|
11212
11199
|
}
|
|
11213
11200
|
return allocIdx;
|
|
11214
11201
|
}
|
|
11215
|
-
//////////////////////////
|
|
11216
|
-
//// Render
|
|
11217
|
-
//////////////////////////
|
|
11218
|
-
/**
|
|
11219
|
-
* Processes a view in the creation mode. This includes a number of steps in a specific order:
|
|
11220
|
-
* - creating view query functions (if any);
|
|
11221
|
-
* - executing a template function in the creation mode;
|
|
11222
|
-
* - updating static queries (if any);
|
|
11223
|
-
* - creating child components defined in a given view.
|
|
11224
|
-
*/
|
|
11225
|
-
function renderView(tView, lView, context) {
|
|
11226
|
-
ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
|
|
11227
|
-
enterView(lView);
|
|
11228
|
-
try {
|
|
11229
|
-
const viewQuery = tView.viewQuery;
|
|
11230
|
-
if (viewQuery !== null) {
|
|
11231
|
-
executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
|
|
11232
|
-
}
|
|
11233
|
-
// Execute a template associated with this view, if it exists. A template function might not be
|
|
11234
|
-
// defined for the root component views.
|
|
11235
|
-
const templateFn = tView.template;
|
|
11236
|
-
if (templateFn !== null) {
|
|
11237
|
-
executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
|
|
11238
|
-
}
|
|
11239
|
-
// This needs to be set before children are processed to support recursive components.
|
|
11240
|
-
// This must be set to false immediately after the first creation run because in an
|
|
11241
|
-
// ngFor loop, all the views will be created together before update mode runs and turns
|
|
11242
|
-
// off firstCreatePass. If we don't set it here, instances will perform directive
|
|
11243
|
-
// matching, etc again and again.
|
|
11244
|
-
if (tView.firstCreatePass) {
|
|
11245
|
-
tView.firstCreatePass = false;
|
|
11246
|
-
}
|
|
11247
|
-
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
|
11248
|
-
// content queries are resolved during change detection (i.e. update mode), after embedded
|
|
11249
|
-
// views are refreshed (see block above).
|
|
11250
|
-
if (tView.staticContentQueries) {
|
|
11251
|
-
refreshContentQueries(tView, lView);
|
|
11252
|
-
}
|
|
11253
|
-
// We must materialize query results before child components are processed
|
|
11254
|
-
// in case a child component has projected a container. The LContainer needs
|
|
11255
|
-
// to exist so the embedded views are properly attached by the container.
|
|
11256
|
-
if (tView.staticViewQueries) {
|
|
11257
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
|
|
11258
|
-
}
|
|
11259
|
-
// Render child component views.
|
|
11260
|
-
const components = tView.components;
|
|
11261
|
-
if (components !== null) {
|
|
11262
|
-
renderChildComponents(lView, components);
|
|
11263
|
-
}
|
|
11264
|
-
}
|
|
11265
|
-
catch (error) {
|
|
11266
|
-
// If we didn't manage to get past the first template pass due to
|
|
11267
|
-
// an error, mark the view as corrupted so we can try to recover.
|
|
11268
|
-
if (tView.firstCreatePass) {
|
|
11269
|
-
tView.incompleteFirstPass = true;
|
|
11270
|
-
tView.firstCreatePass = false;
|
|
11271
|
-
}
|
|
11272
|
-
throw error;
|
|
11273
|
-
}
|
|
11274
|
-
finally {
|
|
11275
|
-
lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
|
|
11276
|
-
leaveView();
|
|
11277
|
-
}
|
|
11278
|
-
}
|
|
11279
|
-
/**
|
|
11280
|
-
* Processes a view in update mode. This includes a number of steps in a specific order:
|
|
11281
|
-
* - executing a template function in update mode;
|
|
11282
|
-
* - executing hooks;
|
|
11283
|
-
* - refreshing queries;
|
|
11284
|
-
* - setting host bindings;
|
|
11285
|
-
* - refreshing child (embedded and component) views.
|
|
11286
|
-
*/
|
|
11287
|
-
function refreshView(tView, lView, templateFn, context) {
|
|
11288
|
-
ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
|
|
11289
|
-
const flags = lView[FLAGS];
|
|
11290
|
-
if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
|
|
11291
|
-
return;
|
|
11292
|
-
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
11293
|
-
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
|
11294
|
-
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
11295
|
-
!isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
|
|
11296
|
-
enterView(lView);
|
|
11297
|
-
try {
|
|
11298
|
-
resetPreOrderHookFlags(lView);
|
|
11299
|
-
setBindingIndex(tView.bindingStartIndex);
|
|
11300
|
-
if (templateFn !== null) {
|
|
11301
|
-
executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
|
|
11302
|
-
}
|
|
11303
|
-
const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
|
|
11304
|
-
// execute pre-order hooks (OnInit, OnChanges, DoCheck)
|
|
11305
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
11306
|
-
if (!isInCheckNoChangesPass) {
|
|
11307
|
-
if (hooksInitPhaseCompleted) {
|
|
11308
|
-
const preOrderCheckHooks = tView.preOrderCheckHooks;
|
|
11309
|
-
if (preOrderCheckHooks !== null) {
|
|
11310
|
-
executeCheckHooks(lView, preOrderCheckHooks, null);
|
|
11311
|
-
}
|
|
11312
|
-
}
|
|
11313
|
-
else {
|
|
11314
|
-
const preOrderHooks = tView.preOrderHooks;
|
|
11315
|
-
if (preOrderHooks !== null) {
|
|
11316
|
-
executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
|
|
11317
|
-
}
|
|
11318
|
-
incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
|
|
11319
|
-
}
|
|
11320
|
-
}
|
|
11321
|
-
// First mark transplanted views that are declared in this lView as needing a refresh at their
|
|
11322
|
-
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
11323
|
-
// `LView` but its declaration appears after the insertion component.
|
|
11324
|
-
markTransplantedViewsForRefresh(lView);
|
|
11325
|
-
refreshEmbeddedViews(lView);
|
|
11326
|
-
// Content query results must be refreshed before content hooks are called.
|
|
11327
|
-
if (tView.contentQueries !== null) {
|
|
11328
|
-
refreshContentQueries(tView, lView);
|
|
11329
|
-
}
|
|
11330
|
-
// execute content hooks (AfterContentInit, AfterContentChecked)
|
|
11331
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
11332
|
-
if (!isInCheckNoChangesPass) {
|
|
11333
|
-
if (hooksInitPhaseCompleted) {
|
|
11334
|
-
const contentCheckHooks = tView.contentCheckHooks;
|
|
11335
|
-
if (contentCheckHooks !== null) {
|
|
11336
|
-
executeCheckHooks(lView, contentCheckHooks);
|
|
11337
|
-
}
|
|
11338
|
-
}
|
|
11339
|
-
else {
|
|
11340
|
-
const contentHooks = tView.contentHooks;
|
|
11341
|
-
if (contentHooks !== null) {
|
|
11342
|
-
executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
11343
|
-
}
|
|
11344
|
-
incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
11345
|
-
}
|
|
11346
|
-
}
|
|
11347
|
-
processHostBindingOpCodes(tView, lView);
|
|
11348
|
-
// Refresh child component views.
|
|
11349
|
-
const components = tView.components;
|
|
11350
|
-
if (components !== null) {
|
|
11351
|
-
refreshChildComponents(lView, components);
|
|
11352
|
-
}
|
|
11353
|
-
// View queries must execute after refreshing child components because a template in this view
|
|
11354
|
-
// could be inserted in a child component. If the view query executes before child component
|
|
11355
|
-
// refresh, the template might not yet be inserted.
|
|
11356
|
-
const viewQuery = tView.viewQuery;
|
|
11357
|
-
if (viewQuery !== null) {
|
|
11358
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
|
|
11359
|
-
}
|
|
11360
|
-
// execute view hooks (AfterViewInit, AfterViewChecked)
|
|
11361
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
11362
|
-
if (!isInCheckNoChangesPass) {
|
|
11363
|
-
if (hooksInitPhaseCompleted) {
|
|
11364
|
-
const viewCheckHooks = tView.viewCheckHooks;
|
|
11365
|
-
if (viewCheckHooks !== null) {
|
|
11366
|
-
executeCheckHooks(lView, viewCheckHooks);
|
|
11367
|
-
}
|
|
11368
|
-
}
|
|
11369
|
-
else {
|
|
11370
|
-
const viewHooks = tView.viewHooks;
|
|
11371
|
-
if (viewHooks !== null) {
|
|
11372
|
-
executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11373
|
-
}
|
|
11374
|
-
incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11375
|
-
}
|
|
11376
|
-
}
|
|
11377
|
-
if (tView.firstUpdatePass === true) {
|
|
11378
|
-
// We need to make sure that we only flip the flag on successful `refreshView` only
|
|
11379
|
-
// Don't do this in `finally` block.
|
|
11380
|
-
// If we did this in `finally` block then an exception could block the execution of styling
|
|
11381
|
-
// instructions which in turn would be unable to insert themselves into the styling linked
|
|
11382
|
-
// list. The result of this would be that if the exception would not be throw on subsequent CD
|
|
11383
|
-
// the styling would be unable to process it data and reflect to the DOM.
|
|
11384
|
-
tView.firstUpdatePass = false;
|
|
11385
|
-
}
|
|
11386
|
-
// Do not reset the dirty state when running in check no changes mode. We don't want components
|
|
11387
|
-
// to behave differently depending on whether check no changes is enabled or not. For example:
|
|
11388
|
-
// Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
|
|
11389
|
-
// refresh a `NgClass` binding should work. If we would reset the dirty state in the check
|
|
11390
|
-
// no changes cycle, the component would be not be dirty for the next update pass. This would
|
|
11391
|
-
// be different in production mode where the component dirty state is not reset.
|
|
11392
|
-
if (!isInCheckNoChangesPass) {
|
|
11393
|
-
lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
|
|
11394
|
-
}
|
|
11395
|
-
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
11396
|
-
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
|
|
11397
|
-
updateTransplantedViewCount(lView[PARENT], -1);
|
|
11398
|
-
}
|
|
11399
|
-
}
|
|
11400
|
-
finally {
|
|
11401
|
-
leaveView();
|
|
11402
|
-
}
|
|
11403
|
-
}
|
|
11404
11202
|
function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
11405
11203
|
const consumer = getReactiveLViewConsumer(lView, REACTIVE_TEMPLATE_CONSUMER);
|
|
11406
11204
|
const prevSelectedIndex = getSelectedIndex();
|
|
@@ -11414,10 +11212,21 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
|
11414
11212
|
}
|
|
11415
11213
|
const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
|
|
11416
11214
|
profiler(preHookType, context);
|
|
11417
|
-
|
|
11215
|
+
if (isUpdatePhase) {
|
|
11216
|
+
consumer.runInContext(templateFn, rf, context);
|
|
11217
|
+
}
|
|
11218
|
+
else {
|
|
11219
|
+
const prevConsumer = setActiveConsumer(null);
|
|
11220
|
+
try {
|
|
11221
|
+
templateFn(rf, context);
|
|
11222
|
+
}
|
|
11223
|
+
finally {
|
|
11224
|
+
setActiveConsumer(prevConsumer);
|
|
11225
|
+
}
|
|
11226
|
+
}
|
|
11418
11227
|
}
|
|
11419
11228
|
finally {
|
|
11420
|
-
if (lView[REACTIVE_TEMPLATE_CONSUMER] === null) {
|
|
11229
|
+
if (isUpdatePhase && lView[REACTIVE_TEMPLATE_CONSUMER] === null) {
|
|
11421
11230
|
commitLViewConsumerIfHasProducers(lView, REACTIVE_TEMPLATE_CONSUMER);
|
|
11422
11231
|
}
|
|
11423
11232
|
setSelectedIndex(prevSelectedIndex);
|
|
@@ -11430,14 +11239,20 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
|
11430
11239
|
//////////////////////////
|
|
11431
11240
|
function executeContentQueries(tView, tNode, lView) {
|
|
11432
11241
|
if (isContentQueryHost(tNode)) {
|
|
11433
|
-
const
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
const
|
|
11437
|
-
|
|
11438
|
-
def
|
|
11242
|
+
const prevConsumer = setActiveConsumer(null);
|
|
11243
|
+
try {
|
|
11244
|
+
const start = tNode.directiveStart;
|
|
11245
|
+
const end = tNode.directiveEnd;
|
|
11246
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
11247
|
+
const def = tView.data[directiveIndex];
|
|
11248
|
+
if (def.contentQueries) {
|
|
11249
|
+
def.contentQueries(1 /* RenderFlags.Create */, lView[directiveIndex], directiveIndex);
|
|
11250
|
+
}
|
|
11439
11251
|
}
|
|
11440
11252
|
}
|
|
11253
|
+
finally {
|
|
11254
|
+
setActiveConsumer(prevConsumer);
|
|
11255
|
+
}
|
|
11441
11256
|
}
|
|
11442
11257
|
}
|
|
11443
11258
|
/**
|
|
@@ -12256,17 +12071,11 @@ function setElementAttribute(renderer, element, namespace, tagName, name, value,
|
|
|
12256
12071
|
function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
|
|
12257
12072
|
const initialInputs = initialInputData[directiveIndex];
|
|
12258
12073
|
if (initialInputs !== null) {
|
|
12259
|
-
const setInput = def.setInput;
|
|
12260
12074
|
for (let i = 0; i < initialInputs.length;) {
|
|
12261
12075
|
const publicName = initialInputs[i++];
|
|
12262
12076
|
const privateName = initialInputs[i++];
|
|
12263
12077
|
const value = initialInputs[i++];
|
|
12264
|
-
|
|
12265
|
-
def.setInput(instance, value, publicName, privateName);
|
|
12266
|
-
}
|
|
12267
|
-
else {
|
|
12268
|
-
instance[privateName] = value;
|
|
12269
|
-
}
|
|
12078
|
+
writeToDirectiveInput(def, instance, publicName, privateName, value);
|
|
12270
12079
|
if (ngDevMode) {
|
|
12271
12080
|
const nativeElement = getNativeByTNode(tNode, lView);
|
|
12272
12081
|
setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
|
|
@@ -12274,6 +12083,20 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
|
|
|
12274
12083
|
}
|
|
12275
12084
|
}
|
|
12276
12085
|
}
|
|
12086
|
+
function writeToDirectiveInput(def, instance, publicName, privateName, value) {
|
|
12087
|
+
const prevConsumer = setActiveConsumer(null);
|
|
12088
|
+
try {
|
|
12089
|
+
if (def.setInput !== null) {
|
|
12090
|
+
def.setInput(instance, value, publicName, privateName);
|
|
12091
|
+
}
|
|
12092
|
+
else {
|
|
12093
|
+
instance[privateName] = value;
|
|
12094
|
+
}
|
|
12095
|
+
}
|
|
12096
|
+
finally {
|
|
12097
|
+
setActiveConsumer(prevConsumer);
|
|
12098
|
+
}
|
|
12099
|
+
}
|
|
12277
12100
|
/**
|
|
12278
12101
|
* Generates initialInputData for a node and stores it in the template's static storage
|
|
12279
12102
|
* so subsequent template invocations don't have to recalculate it.
|
|
@@ -12358,151 +12181,24 @@ function createLContainer(hostNative, currentView, native, tNode) {
|
|
|
12358
12181
|
assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
|
|
12359
12182
|
return lContainer;
|
|
12360
12183
|
}
|
|
12361
|
-
/**
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
}
|
|
12376
|
-
}
|
|
12377
|
-
/**
|
|
12378
|
-
* Mark transplanted views as needing to be refreshed at their insertion points.
|
|
12379
|
-
*
|
|
12380
|
-
* @param lView The `LView` that may have transplanted views.
|
|
12381
|
-
*/
|
|
12382
|
-
function markTransplantedViewsForRefresh(lView) {
|
|
12383
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12384
|
-
if (!lContainer[HAS_TRANSPLANTED_VIEWS])
|
|
12385
|
-
continue;
|
|
12386
|
-
const movedViews = lContainer[MOVED_VIEWS];
|
|
12387
|
-
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
|
|
12388
|
-
for (let i = 0; i < movedViews.length; i++) {
|
|
12389
|
-
const movedLView = movedViews[i];
|
|
12390
|
-
const insertionLContainer = movedLView[PARENT];
|
|
12391
|
-
ngDevMode && assertLContainer(insertionLContainer);
|
|
12392
|
-
// We don't want to increment the counter if the moved LView was already marked for
|
|
12393
|
-
// refresh.
|
|
12394
|
-
if ((movedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) === 0) {
|
|
12395
|
-
updateTransplantedViewCount(insertionLContainer, 1);
|
|
12396
|
-
}
|
|
12397
|
-
// Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
|
|
12398
|
-
// those that aren't (declaration component === insertion component). In the latter case,
|
|
12399
|
-
// it's fine to add the flag, as we will clear it immediately in
|
|
12400
|
-
// `refreshEmbeddedViews` for the view currently being refreshed.
|
|
12401
|
-
movedLView[FLAGS] |= 1024 /* LViewFlags.RefreshTransplantedView */;
|
|
12402
|
-
}
|
|
12403
|
-
}
|
|
12404
|
-
}
|
|
12405
|
-
/////////////
|
|
12406
|
-
/**
|
|
12407
|
-
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12408
|
-
*
|
|
12409
|
-
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12410
|
-
*/
|
|
12411
|
-
function refreshComponent(hostLView, componentHostIdx) {
|
|
12412
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12413
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12414
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12415
|
-
if (viewAttachedToChangeDetector(componentView)) {
|
|
12416
|
-
const tView = componentView[TVIEW];
|
|
12417
|
-
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12418
|
-
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12419
|
-
}
|
|
12420
|
-
else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12421
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12422
|
-
refreshContainsDirtyView(componentView);
|
|
12423
|
-
}
|
|
12424
|
-
}
|
|
12425
|
-
}
|
|
12426
|
-
/**
|
|
12427
|
-
* Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
|
|
12428
|
-
* children or descendants of the given lView.
|
|
12429
|
-
*
|
|
12430
|
-
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12431
|
-
*/
|
|
12432
|
-
function refreshContainsDirtyView(lView) {
|
|
12433
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12434
|
-
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12435
|
-
const embeddedLView = lContainer[i];
|
|
12436
|
-
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12437
|
-
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
12438
|
-
const embeddedTView = embeddedLView[TVIEW];
|
|
12439
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12440
|
-
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12441
|
-
}
|
|
12442
|
-
else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12443
|
-
refreshContainsDirtyView(embeddedLView);
|
|
12444
|
-
}
|
|
12445
|
-
}
|
|
12446
|
-
}
|
|
12447
|
-
}
|
|
12448
|
-
const tView = lView[TVIEW];
|
|
12449
|
-
// Refresh child component views.
|
|
12450
|
-
const components = tView.components;
|
|
12451
|
-
if (components !== null) {
|
|
12452
|
-
for (let i = 0; i < components.length; i++) {
|
|
12453
|
-
const componentView = getComponentLViewByIndex(components[i], lView);
|
|
12454
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12455
|
-
if (viewAttachedToChangeDetector(componentView) &&
|
|
12456
|
-
componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12457
|
-
refreshContainsDirtyView(componentView);
|
|
12184
|
+
/** Refreshes all content queries declared by directives in a given view */
|
|
12185
|
+
function refreshContentQueries(tView, lView) {
|
|
12186
|
+
const contentQueries = tView.contentQueries;
|
|
12187
|
+
if (contentQueries !== null) {
|
|
12188
|
+
for (let i = 0; i < contentQueries.length; i += 2) {
|
|
12189
|
+
const queryStartIdx = contentQueries[i];
|
|
12190
|
+
const directiveDefIdx = contentQueries[i + 1];
|
|
12191
|
+
if (directiveDefIdx !== -1) {
|
|
12192
|
+
const directiveDef = tView.data[directiveDefIdx];
|
|
12193
|
+
ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
|
|
12194
|
+
ngDevMode &&
|
|
12195
|
+
assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
|
|
12196
|
+
setCurrentQueryIndex(queryStartIdx);
|
|
12197
|
+
directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
|
|
12458
12198
|
}
|
|
12459
12199
|
}
|
|
12460
12200
|
}
|
|
12461
12201
|
}
|
|
12462
|
-
function renderComponent(hostLView, componentHostIdx) {
|
|
12463
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
|
|
12464
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12465
|
-
const componentTView = componentView[TVIEW];
|
|
12466
|
-
syncViewWithBlueprint(componentTView, componentView);
|
|
12467
|
-
const hostRNode = componentView[HOST];
|
|
12468
|
-
// Populate an LView with hydration info retrieved from the DOM via TransferState.
|
|
12469
|
-
if (hostRNode !== null && componentView[HYDRATION] === null) {
|
|
12470
|
-
componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
|
|
12471
|
-
}
|
|
12472
|
-
renderView(componentTView, componentView, componentView[CONTEXT]);
|
|
12473
|
-
}
|
|
12474
|
-
/**
|
|
12475
|
-
* Syncs an LView instance with its blueprint if they have gotten out of sync.
|
|
12476
|
-
*
|
|
12477
|
-
* Typically, blueprints and their view instances should always be in sync, so the loop here
|
|
12478
|
-
* will be skipped. However, consider this case of two components side-by-side:
|
|
12479
|
-
*
|
|
12480
|
-
* App template:
|
|
12481
|
-
* ```
|
|
12482
|
-
* <comp></comp>
|
|
12483
|
-
* <comp></comp>
|
|
12484
|
-
* ```
|
|
12485
|
-
*
|
|
12486
|
-
* The following will happen:
|
|
12487
|
-
* 1. App template begins processing.
|
|
12488
|
-
* 2. First <comp> is matched as a component and its LView is created.
|
|
12489
|
-
* 3. Second <comp> is matched as a component and its LView is created.
|
|
12490
|
-
* 4. App template completes processing, so it's time to check child templates.
|
|
12491
|
-
* 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
|
|
12492
|
-
* 6. Second <comp> template is checked. Its blueprint has been updated by the first
|
|
12493
|
-
* <comp> template, but its LView was created before this update, so it is out of sync.
|
|
12494
|
-
*
|
|
12495
|
-
* Note that embedded views inside ngFor loops will never be out of sync because these views
|
|
12496
|
-
* are processed as soon as they are created.
|
|
12497
|
-
*
|
|
12498
|
-
* @param tView The `TView` that contains the blueprint for syncing
|
|
12499
|
-
* @param lView The view to sync
|
|
12500
|
-
*/
|
|
12501
|
-
function syncViewWithBlueprint(tView, lView) {
|
|
12502
|
-
for (let i = lView.length; i < tView.blueprint.length; i++) {
|
|
12503
|
-
lView.push(tView.blueprint[i]);
|
|
12504
|
-
}
|
|
12505
|
-
}
|
|
12506
12202
|
/**
|
|
12507
12203
|
* Adds LView or LContainer to the end of the current view tree.
|
|
12508
12204
|
*
|
|
@@ -12531,45 +12227,17 @@ function addToViewTree(lView, lViewOrLContainer) {
|
|
|
12531
12227
|
///////////////////////////////
|
|
12532
12228
|
//// Change detection
|
|
12533
12229
|
///////////////////////////////
|
|
12534
|
-
function
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12538
|
-
// to avoid any possible side-effects.
|
|
12539
|
-
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
|
12540
|
-
if (!checkNoChangesMode && rendererFactory.begin)
|
|
12541
|
-
rendererFactory.begin();
|
|
12542
|
-
try {
|
|
12543
|
-
refreshView(tView, lView, tView.template, context);
|
|
12544
|
-
}
|
|
12545
|
-
catch (error) {
|
|
12546
|
-
if (notifyErrorHandler) {
|
|
12547
|
-
handleError(lView, error);
|
|
12548
|
-
}
|
|
12549
|
-
throw error;
|
|
12550
|
-
}
|
|
12551
|
-
finally {
|
|
12552
|
-
if (!checkNoChangesMode && rendererFactory.end)
|
|
12553
|
-
rendererFactory.end();
|
|
12554
|
-
// One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
|
|
12555
|
-
// other post-order hooks.
|
|
12556
|
-
!checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
|
|
12557
|
-
}
|
|
12558
|
-
}
|
|
12559
|
-
function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12560
|
-
setIsInCheckNoChangesMode(true);
|
|
12230
|
+
function executeViewQueryFn(flags, viewQueryFn, component) {
|
|
12231
|
+
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
|
|
12232
|
+
setCurrentQueryIndex(0);
|
|
12233
|
+
const prevConsumer = setActiveConsumer(null);
|
|
12561
12234
|
try {
|
|
12562
|
-
|
|
12235
|
+
viewQueryFn(flags, component);
|
|
12563
12236
|
}
|
|
12564
12237
|
finally {
|
|
12565
|
-
|
|
12238
|
+
setActiveConsumer(prevConsumer);
|
|
12566
12239
|
}
|
|
12567
12240
|
}
|
|
12568
|
-
function executeViewQueryFn(flags, viewQueryFn, component) {
|
|
12569
|
-
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
|
|
12570
|
-
setCurrentQueryIndex(0);
|
|
12571
|
-
viewQueryFn(flags, component);
|
|
12572
|
-
}
|
|
12573
12241
|
///////////////////////////////
|
|
12574
12242
|
//// Bindings & interpolations
|
|
12575
12243
|
///////////////////////////////
|
|
@@ -12656,12 +12324,7 @@ function setInputsForProperty(tView, lView, inputs, publicName, value) {
|
|
|
12656
12324
|
const instance = lView[index];
|
|
12657
12325
|
ngDevMode && assertIndexInRange(lView, index);
|
|
12658
12326
|
const def = tView.data[index];
|
|
12659
|
-
|
|
12660
|
-
def.setInput(instance, value, publicName, privateName);
|
|
12661
|
-
}
|
|
12662
|
-
else {
|
|
12663
|
-
instance[privateName] = value;
|
|
12664
|
-
}
|
|
12327
|
+
writeToDirectiveInput(def, instance, publicName, privateName, value);
|
|
12665
12328
|
}
|
|
12666
12329
|
}
|
|
12667
12330
|
/**
|
|
@@ -12676,185 +12339,582 @@ function textBindingInternal(lView, index, value) {
|
|
|
12676
12339
|
updateTextNode(lView[RENDERER], element, value);
|
|
12677
12340
|
}
|
|
12678
12341
|
|
|
12342
|
+
function renderComponent(hostLView, componentHostIdx) {
|
|
12343
|
+
ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
|
|
12344
|
+
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12345
|
+
const componentTView = componentView[TVIEW];
|
|
12346
|
+
syncViewWithBlueprint(componentTView, componentView);
|
|
12347
|
+
const hostRNode = componentView[HOST];
|
|
12348
|
+
// Populate an LView with hydration info retrieved from the DOM via TransferState.
|
|
12349
|
+
if (hostRNode !== null && componentView[HYDRATION] === null) {
|
|
12350
|
+
componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
|
|
12351
|
+
}
|
|
12352
|
+
renderView(componentTView, componentView, componentView[CONTEXT]);
|
|
12353
|
+
}
|
|
12679
12354
|
/**
|
|
12680
|
-
*
|
|
12681
|
-
* The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
|
|
12682
|
-
* is injected in a component or directive, the callbacks run when that component or
|
|
12683
|
-
* directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
|
|
12355
|
+
* Syncs an LView instance with its blueprint if they have gotten out of sync.
|
|
12684
12356
|
*
|
|
12685
|
-
*
|
|
12357
|
+
* Typically, blueprints and their view instances should always be in sync, so the loop here
|
|
12358
|
+
* will be skipped. However, consider this case of two components side-by-side:
|
|
12359
|
+
*
|
|
12360
|
+
* App template:
|
|
12361
|
+
* ```
|
|
12362
|
+
* <comp></comp>
|
|
12363
|
+
* <comp></comp>
|
|
12364
|
+
* ```
|
|
12365
|
+
*
|
|
12366
|
+
* The following will happen:
|
|
12367
|
+
* 1. App template begins processing.
|
|
12368
|
+
* 2. First <comp> is matched as a component and its LView is created.
|
|
12369
|
+
* 3. Second <comp> is matched as a component and its LView is created.
|
|
12370
|
+
* 4. App template completes processing, so it's time to check child templates.
|
|
12371
|
+
* 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
|
|
12372
|
+
* 6. Second <comp> template is checked. Its blueprint has been updated by the first
|
|
12373
|
+
* <comp> template, but its LView was created before this update, so it is out of sync.
|
|
12374
|
+
*
|
|
12375
|
+
* Note that embedded views inside ngFor loops will never be out of sync because these views
|
|
12376
|
+
* are processed as soon as they are created.
|
|
12377
|
+
*
|
|
12378
|
+
* @param tView The `TView` that contains the blueprint for syncing
|
|
12379
|
+
* @param lView The view to sync
|
|
12686
12380
|
*/
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
*/
|
|
12692
|
-
static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
|
|
12693
|
-
/**
|
|
12694
|
-
* @internal
|
|
12695
|
-
* @nocollapse
|
|
12696
|
-
*/
|
|
12697
|
-
static { this.__NG_ENV_ID__ = (injector) => injector; }
|
|
12381
|
+
function syncViewWithBlueprint(tView, lView) {
|
|
12382
|
+
for (let i = lView.length; i < tView.blueprint.length; i++) {
|
|
12383
|
+
lView.push(tView.blueprint[i]);
|
|
12384
|
+
}
|
|
12698
12385
|
}
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12386
|
+
/**
|
|
12387
|
+
* Processes a view in the creation mode. This includes a number of steps in a specific order:
|
|
12388
|
+
* - creating view query functions (if any);
|
|
12389
|
+
* - executing a template function in the creation mode;
|
|
12390
|
+
* - updating static queries (if any);
|
|
12391
|
+
* - creating child components defined in a given view.
|
|
12392
|
+
*/
|
|
12393
|
+
function renderView(tView, lView, context) {
|
|
12394
|
+
ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
|
|
12395
|
+
enterView(lView);
|
|
12396
|
+
try {
|
|
12397
|
+
const viewQuery = tView.viewQuery;
|
|
12398
|
+
if (viewQuery !== null) {
|
|
12399
|
+
executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
|
|
12400
|
+
}
|
|
12401
|
+
// Execute a template associated with this view, if it exists. A template function might not be
|
|
12402
|
+
// defined for the root component views.
|
|
12403
|
+
const templateFn = tView.template;
|
|
12404
|
+
if (templateFn !== null) {
|
|
12405
|
+
executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
|
|
12406
|
+
}
|
|
12407
|
+
// This needs to be set before children are processed to support recursive components.
|
|
12408
|
+
// This must be set to false immediately after the first creation run because in an
|
|
12409
|
+
// ngFor loop, all the views will be created together before update mode runs and turns
|
|
12410
|
+
// off firstCreatePass. If we don't set it here, instances will perform directive
|
|
12411
|
+
// matching, etc again and again.
|
|
12412
|
+
if (tView.firstCreatePass) {
|
|
12413
|
+
tView.firstCreatePass = false;
|
|
12414
|
+
}
|
|
12415
|
+
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
|
12416
|
+
// content queries are resolved during change detection (i.e. update mode), after embedded
|
|
12417
|
+
// views are refreshed (see block above).
|
|
12418
|
+
if (tView.staticContentQueries) {
|
|
12419
|
+
refreshContentQueries(tView, lView);
|
|
12420
|
+
}
|
|
12421
|
+
// We must materialize query results before child components are processed
|
|
12422
|
+
// in case a child component has projected a container. The LContainer needs
|
|
12423
|
+
// to exist so the embedded views are properly attached by the container.
|
|
12424
|
+
if (tView.staticViewQueries) {
|
|
12425
|
+
executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
|
|
12426
|
+
}
|
|
12427
|
+
// Render child component views.
|
|
12428
|
+
const components = tView.components;
|
|
12429
|
+
if (components !== null) {
|
|
12430
|
+
renderChildComponents(lView, components);
|
|
12431
|
+
}
|
|
12432
|
+
}
|
|
12433
|
+
catch (error) {
|
|
12434
|
+
// If we didn't manage to get past the first template pass due to
|
|
12435
|
+
// an error, mark the view as corrupted so we can try to recover.
|
|
12436
|
+
if (tView.firstCreatePass) {
|
|
12437
|
+
tView.incompleteFirstPass = true;
|
|
12438
|
+
tView.firstCreatePass = false;
|
|
12439
|
+
}
|
|
12440
|
+
throw error;
|
|
12441
|
+
}
|
|
12442
|
+
finally {
|
|
12443
|
+
lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
|
|
12444
|
+
leaveView();
|
|
12445
|
+
}
|
|
12446
|
+
}
|
|
12447
|
+
/** Renders child components in the current view (creation mode). */
|
|
12448
|
+
function renderChildComponents(hostLView, components) {
|
|
12449
|
+
for (let i = 0; i < components.length; i++) {
|
|
12450
|
+
renderComponent(hostLView, components[i]);
|
|
12451
|
+
}
|
|
12452
|
+
}
|
|
12453
|
+
|
|
12454
|
+
/**
|
|
12455
|
+
* `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
|
|
12456
|
+
* The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
|
|
12457
|
+
* is injected in a component or directive, the callbacks run when that component or
|
|
12458
|
+
* directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
|
|
12459
|
+
*
|
|
12460
|
+
* @publicApi
|
|
12461
|
+
*/
|
|
12462
|
+
class DestroyRef {
|
|
12463
|
+
/**
|
|
12464
|
+
* @internal
|
|
12465
|
+
* @nocollapse
|
|
12466
|
+
*/
|
|
12467
|
+
static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
|
|
12468
|
+
/**
|
|
12469
|
+
* @internal
|
|
12470
|
+
* @nocollapse
|
|
12471
|
+
*/
|
|
12472
|
+
static { this.__NG_ENV_ID__ = (injector) => injector; }
|
|
12473
|
+
}
|
|
12474
|
+
class NodeInjectorDestroyRef extends DestroyRef {
|
|
12475
|
+
constructor(_lView) {
|
|
12476
|
+
super();
|
|
12477
|
+
this._lView = _lView;
|
|
12478
|
+
}
|
|
12479
|
+
onDestroy(callback) {
|
|
12480
|
+
storeLViewOnDestroy(this._lView, callback);
|
|
12481
|
+
return () => removeLViewOnDestroy(this._lView, callback);
|
|
12482
|
+
}
|
|
12483
|
+
}
|
|
12484
|
+
function injectDestroyRef() {
|
|
12485
|
+
return new NodeInjectorDestroyRef(getLView());
|
|
12486
|
+
}
|
|
12487
|
+
|
|
12488
|
+
/**
|
|
12489
|
+
* Tracks all effects registered within a given application and runs them via `flush`.
|
|
12490
|
+
*/
|
|
12491
|
+
class EffectManager {
|
|
12492
|
+
constructor() {
|
|
12493
|
+
this.all = new Set();
|
|
12494
|
+
this.queue = new Map();
|
|
12495
|
+
}
|
|
12496
|
+
create(effectFn, destroyRef, allowSignalWrites) {
|
|
12497
|
+
const zone = (typeof Zone === 'undefined') ? null : Zone.current;
|
|
12498
|
+
const watch = new Watch(effectFn, (watch) => {
|
|
12499
|
+
if (!this.all.has(watch)) {
|
|
12500
|
+
return;
|
|
12501
|
+
}
|
|
12502
|
+
this.queue.set(watch, zone);
|
|
12503
|
+
}, allowSignalWrites);
|
|
12504
|
+
this.all.add(watch);
|
|
12505
|
+
// Effects start dirty.
|
|
12506
|
+
watch.notify();
|
|
12507
|
+
let unregisterOnDestroy;
|
|
12508
|
+
const destroy = () => {
|
|
12509
|
+
watch.cleanup();
|
|
12510
|
+
unregisterOnDestroy?.();
|
|
12511
|
+
this.all.delete(watch);
|
|
12512
|
+
this.queue.delete(watch);
|
|
12513
|
+
};
|
|
12514
|
+
unregisterOnDestroy = destroyRef?.onDestroy(destroy);
|
|
12515
|
+
return {
|
|
12516
|
+
destroy,
|
|
12517
|
+
};
|
|
12518
|
+
}
|
|
12519
|
+
flush() {
|
|
12520
|
+
if (this.queue.size === 0) {
|
|
12521
|
+
return;
|
|
12522
|
+
}
|
|
12523
|
+
for (const [watch, zone] of this.queue) {
|
|
12524
|
+
this.queue.delete(watch);
|
|
12525
|
+
if (zone) {
|
|
12526
|
+
zone.run(() => watch.run());
|
|
12527
|
+
}
|
|
12528
|
+
else {
|
|
12529
|
+
watch.run();
|
|
12530
|
+
}
|
|
12531
|
+
}
|
|
12532
|
+
}
|
|
12533
|
+
get isQueueEmpty() {
|
|
12534
|
+
return this.queue.size === 0;
|
|
12535
|
+
}
|
|
12536
|
+
/** @nocollapse */
|
|
12537
|
+
static { this.ɵprov = ɵɵdefineInjectable({
|
|
12538
|
+
token: EffectManager,
|
|
12539
|
+
providedIn: 'root',
|
|
12540
|
+
factory: () => new EffectManager(),
|
|
12541
|
+
}); }
|
|
12542
|
+
}
|
|
12543
|
+
/**
|
|
12544
|
+
* Create a global `Effect` for the given reactive function.
|
|
12545
|
+
*
|
|
12546
|
+
* @developerPreview
|
|
12547
|
+
*/
|
|
12548
|
+
function effect(effectFn, options) {
|
|
12549
|
+
!options?.injector && assertInInjectionContext(effect);
|
|
12550
|
+
const injector = options?.injector ?? inject$1(Injector);
|
|
12551
|
+
const effectManager = injector.get(EffectManager);
|
|
12552
|
+
const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
|
|
12553
|
+
return effectManager.create(effectFn, destroyRef, !!options?.allowSignalWrites);
|
|
12554
|
+
}
|
|
12555
|
+
|
|
12556
|
+
/**
|
|
12557
|
+
* Compute the static styling (class/style) from `TAttributes`.
|
|
12558
|
+
*
|
|
12559
|
+
* This function should be called during `firstCreatePass` only.
|
|
12560
|
+
*
|
|
12561
|
+
* @param tNode The `TNode` into which the styling information should be loaded.
|
|
12562
|
+
* @param attrs `TAttributes` containing the styling information.
|
|
12563
|
+
* @param writeToHost Where should the resulting static styles be written?
|
|
12564
|
+
* - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
|
|
12565
|
+
* - `true` Write to `TNode.styles` / `TNode.classes`
|
|
12566
|
+
*/
|
|
12567
|
+
function computeStaticStyling(tNode, attrs, writeToHost) {
|
|
12568
|
+
ngDevMode &&
|
|
12569
|
+
assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
|
|
12570
|
+
let styles = writeToHost ? tNode.styles : null;
|
|
12571
|
+
let classes = writeToHost ? tNode.classes : null;
|
|
12572
|
+
let mode = 0;
|
|
12573
|
+
if (attrs !== null) {
|
|
12574
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
12575
|
+
const value = attrs[i];
|
|
12576
|
+
if (typeof value === 'number') {
|
|
12577
|
+
mode = value;
|
|
12578
|
+
}
|
|
12579
|
+
else if (mode == 1 /* AttributeMarker.Classes */) {
|
|
12580
|
+
classes = concatStringsWithSpace(classes, value);
|
|
12581
|
+
}
|
|
12582
|
+
else if (mode == 2 /* AttributeMarker.Styles */) {
|
|
12583
|
+
const style = value;
|
|
12584
|
+
const styleValue = attrs[++i];
|
|
12585
|
+
styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
|
|
12586
|
+
}
|
|
12587
|
+
}
|
|
12588
|
+
}
|
|
12589
|
+
writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
|
|
12590
|
+
writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
|
|
12591
|
+
}
|
|
12592
|
+
|
|
12593
|
+
function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
|
|
12594
|
+
while (tNode !== null) {
|
|
12595
|
+
ngDevMode &&
|
|
12596
|
+
assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
|
|
12597
|
+
const lNode = lView[tNode.index];
|
|
12598
|
+
if (lNode !== null) {
|
|
12599
|
+
result.push(unwrapRNode(lNode));
|
|
12600
|
+
}
|
|
12601
|
+
// A given lNode can represent either a native node or a LContainer (when it is a host of a
|
|
12602
|
+
// ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
|
|
12603
|
+
// from the views in this container.
|
|
12604
|
+
if (isLContainer(lNode)) {
|
|
12605
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
|
|
12606
|
+
const lViewInAContainer = lNode[i];
|
|
12607
|
+
const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
|
|
12608
|
+
if (lViewFirstChildTNode !== null) {
|
|
12609
|
+
collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
|
|
12610
|
+
}
|
|
12611
|
+
}
|
|
12612
|
+
// When an LContainer is created, the anchor (comment) node is:
|
|
12613
|
+
// - (1) either reused in case of an ElementContainer (<ng-container>)
|
|
12614
|
+
// - (2) or a new comment node is created
|
|
12615
|
+
// In the first case, the anchor comment node would be added to the final
|
|
12616
|
+
// list by the code above (`result.push(unwrapRNode(lNode))`), but the second
|
|
12617
|
+
// case requires extra handling: the anchor node needs to be added to the
|
|
12618
|
+
// final list manually. See additional information in the `createAnchorNode`
|
|
12619
|
+
// function in the `view_container_ref.ts`.
|
|
12620
|
+
//
|
|
12621
|
+
// In the first case, the same reference would be stored in the `NATIVE`
|
|
12622
|
+
// and `HOST` slots in an LContainer. Otherwise, this is the second case and
|
|
12623
|
+
// we should add an element to the final list.
|
|
12624
|
+
if (lNode[NATIVE] !== lNode[HOST]) {
|
|
12625
|
+
result.push(lNode[NATIVE]);
|
|
12626
|
+
}
|
|
12627
|
+
}
|
|
12628
|
+
const tNodeType = tNode.type;
|
|
12629
|
+
if (tNodeType & 8 /* TNodeType.ElementContainer */) {
|
|
12630
|
+
collectNativeNodes(tView, lView, tNode.child, result);
|
|
12631
|
+
}
|
|
12632
|
+
else if (tNodeType & 32 /* TNodeType.Icu */) {
|
|
12633
|
+
const nextRNode = icuContainerIterate(tNode, lView);
|
|
12634
|
+
let rNode;
|
|
12635
|
+
while (rNode = nextRNode()) {
|
|
12636
|
+
result.push(rNode);
|
|
12637
|
+
}
|
|
12638
|
+
}
|
|
12639
|
+
else if (tNodeType & 16 /* TNodeType.Projection */) {
|
|
12640
|
+
const nodesInSlot = getProjectionNodes(lView, tNode);
|
|
12641
|
+
if (Array.isArray(nodesInSlot)) {
|
|
12642
|
+
result.push(...nodesInSlot);
|
|
12643
|
+
}
|
|
12644
|
+
else {
|
|
12645
|
+
const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
|
|
12646
|
+
ngDevMode && assertParentView(parentView);
|
|
12647
|
+
collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
|
|
12648
|
+
}
|
|
12649
|
+
}
|
|
12650
|
+
tNode = isProjection ? tNode.projectionNext : tNode.next;
|
|
12651
|
+
}
|
|
12652
|
+
return result;
|
|
12653
|
+
}
|
|
12654
|
+
|
|
12655
|
+
function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12656
|
+
const rendererFactory = lView[ENVIRONMENT].rendererFactory;
|
|
12657
|
+
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
12658
|
+
// since they were assigned. We do not want to invoke renderer factory functions in that mode
|
|
12659
|
+
// to avoid any possible side-effects.
|
|
12660
|
+
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
|
12661
|
+
if (!checkNoChangesMode && rendererFactory.begin)
|
|
12662
|
+
rendererFactory.begin();
|
|
12663
|
+
try {
|
|
12664
|
+
refreshView(tView, lView, tView.template, context);
|
|
12665
|
+
}
|
|
12666
|
+
catch (error) {
|
|
12667
|
+
if (notifyErrorHandler) {
|
|
12668
|
+
handleError(lView, error);
|
|
12669
|
+
}
|
|
12670
|
+
throw error;
|
|
12671
|
+
}
|
|
12672
|
+
finally {
|
|
12673
|
+
if (!checkNoChangesMode && rendererFactory.end)
|
|
12674
|
+
rendererFactory.end();
|
|
12675
|
+
// One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
|
|
12676
|
+
// other post-order hooks.
|
|
12677
|
+
!checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
|
|
12678
|
+
}
|
|
12679
|
+
}
|
|
12680
|
+
function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12681
|
+
setIsInCheckNoChangesMode(true);
|
|
12682
|
+
try {
|
|
12683
|
+
detectChangesInternal(tView, lView, context, notifyErrorHandler);
|
|
12684
|
+
}
|
|
12685
|
+
finally {
|
|
12686
|
+
setIsInCheckNoChangesMode(false);
|
|
12687
|
+
}
|
|
12688
|
+
}
|
|
12689
|
+
/**
|
|
12690
|
+
* Synchronously perform change detection on a component (and possibly its sub-components).
|
|
12691
|
+
*
|
|
12692
|
+
* This function triggers change detection in a synchronous way on a component.
|
|
12693
|
+
*
|
|
12694
|
+
* @param component The component which the change detection should be performed on.
|
|
12695
|
+
*/
|
|
12696
|
+
function detectChanges(component) {
|
|
12697
|
+
const view = getComponentViewByInstance(component);
|
|
12698
|
+
detectChangesInternal(view[TVIEW], view, component);
|
|
12699
|
+
}
|
|
12700
|
+
/**
|
|
12701
|
+
* Processes a view in update mode. This includes a number of steps in a specific order:
|
|
12702
|
+
* - executing a template function in update mode;
|
|
12703
|
+
* - executing hooks;
|
|
12704
|
+
* - refreshing queries;
|
|
12705
|
+
* - setting host bindings;
|
|
12706
|
+
* - refreshing child (embedded and component) views.
|
|
12707
|
+
*/
|
|
12708
|
+
function refreshView(tView, lView, templateFn, context) {
|
|
12709
|
+
ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
|
|
12710
|
+
const flags = lView[FLAGS];
|
|
12711
|
+
if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
|
|
12712
|
+
return;
|
|
12713
|
+
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
12714
|
+
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
|
12715
|
+
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
12716
|
+
!isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
|
|
12717
|
+
enterView(lView);
|
|
12718
|
+
try {
|
|
12719
|
+
resetPreOrderHookFlags(lView);
|
|
12720
|
+
setBindingIndex(tView.bindingStartIndex);
|
|
12721
|
+
if (templateFn !== null) {
|
|
12722
|
+
executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
|
|
12723
|
+
}
|
|
12724
|
+
const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
|
|
12725
|
+
// execute pre-order hooks (OnInit, OnChanges, DoCheck)
|
|
12726
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12727
|
+
if (!isInCheckNoChangesPass) {
|
|
12728
|
+
if (hooksInitPhaseCompleted) {
|
|
12729
|
+
const preOrderCheckHooks = tView.preOrderCheckHooks;
|
|
12730
|
+
if (preOrderCheckHooks !== null) {
|
|
12731
|
+
executeCheckHooks(lView, preOrderCheckHooks, null);
|
|
12732
|
+
}
|
|
12733
|
+
}
|
|
12734
|
+
else {
|
|
12735
|
+
const preOrderHooks = tView.preOrderHooks;
|
|
12736
|
+
if (preOrderHooks !== null) {
|
|
12737
|
+
executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
|
|
12738
|
+
}
|
|
12739
|
+
incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
|
|
12740
|
+
}
|
|
12741
|
+
}
|
|
12742
|
+
// First mark transplanted views that are declared in this lView as needing a refresh at their
|
|
12743
|
+
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
12744
|
+
// `LView` but its declaration appears after the insertion component.
|
|
12745
|
+
markTransplantedViewsForRefresh(lView);
|
|
12746
|
+
refreshEmbeddedViews(lView);
|
|
12747
|
+
// Content query results must be refreshed before content hooks are called.
|
|
12748
|
+
if (tView.contentQueries !== null) {
|
|
12749
|
+
refreshContentQueries(tView, lView);
|
|
12750
|
+
}
|
|
12751
|
+
// execute content hooks (AfterContentInit, AfterContentChecked)
|
|
12752
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12753
|
+
if (!isInCheckNoChangesPass) {
|
|
12754
|
+
if (hooksInitPhaseCompleted) {
|
|
12755
|
+
const contentCheckHooks = tView.contentCheckHooks;
|
|
12756
|
+
if (contentCheckHooks !== null) {
|
|
12757
|
+
executeCheckHooks(lView, contentCheckHooks);
|
|
12758
|
+
}
|
|
12759
|
+
}
|
|
12760
|
+
else {
|
|
12761
|
+
const contentHooks = tView.contentHooks;
|
|
12762
|
+
if (contentHooks !== null) {
|
|
12763
|
+
executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
12764
|
+
}
|
|
12765
|
+
incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
12766
|
+
}
|
|
12767
|
+
}
|
|
12768
|
+
processHostBindingOpCodes(tView, lView);
|
|
12769
|
+
// Refresh child component views.
|
|
12770
|
+
const components = tView.components;
|
|
12771
|
+
if (components !== null) {
|
|
12772
|
+
refreshChildComponents(lView, components);
|
|
12773
|
+
}
|
|
12774
|
+
// View queries must execute after refreshing child components because a template in this view
|
|
12775
|
+
// could be inserted in a child component. If the view query executes before child component
|
|
12776
|
+
// refresh, the template might not yet be inserted.
|
|
12777
|
+
const viewQuery = tView.viewQuery;
|
|
12778
|
+
if (viewQuery !== null) {
|
|
12779
|
+
executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
|
|
12780
|
+
}
|
|
12781
|
+
// execute view hooks (AfterViewInit, AfterViewChecked)
|
|
12782
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12783
|
+
if (!isInCheckNoChangesPass) {
|
|
12784
|
+
if (hooksInitPhaseCompleted) {
|
|
12785
|
+
const viewCheckHooks = tView.viewCheckHooks;
|
|
12786
|
+
if (viewCheckHooks !== null) {
|
|
12787
|
+
executeCheckHooks(lView, viewCheckHooks);
|
|
12788
|
+
}
|
|
12789
|
+
}
|
|
12790
|
+
else {
|
|
12791
|
+
const viewHooks = tView.viewHooks;
|
|
12792
|
+
if (viewHooks !== null) {
|
|
12793
|
+
executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
12794
|
+
}
|
|
12795
|
+
incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
12796
|
+
}
|
|
12797
|
+
}
|
|
12798
|
+
if (tView.firstUpdatePass === true) {
|
|
12799
|
+
// We need to make sure that we only flip the flag on successful `refreshView` only
|
|
12800
|
+
// Don't do this in `finally` block.
|
|
12801
|
+
// If we did this in `finally` block then an exception could block the execution of styling
|
|
12802
|
+
// instructions which in turn would be unable to insert themselves into the styling linked
|
|
12803
|
+
// list. The result of this would be that if the exception would not be throw on subsequent CD
|
|
12804
|
+
// the styling would be unable to process it data and reflect to the DOM.
|
|
12805
|
+
tView.firstUpdatePass = false;
|
|
12806
|
+
}
|
|
12807
|
+
// Do not reset the dirty state when running in check no changes mode. We don't want components
|
|
12808
|
+
// to behave differently depending on whether check no changes is enabled or not. For example:
|
|
12809
|
+
// Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
|
|
12810
|
+
// refresh a `NgClass` binding should work. If we would reset the dirty state in the check
|
|
12811
|
+
// no changes cycle, the component would be not be dirty for the next update pass. This would
|
|
12812
|
+
// be different in production mode where the component dirty state is not reset.
|
|
12813
|
+
if (!isInCheckNoChangesPass) {
|
|
12814
|
+
lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
|
|
12815
|
+
}
|
|
12816
|
+
clearViewRefreshFlag(lView);
|
|
12703
12817
|
}
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
return () => removeLViewOnDestroy(this._lView, callback);
|
|
12818
|
+
finally {
|
|
12819
|
+
leaveView();
|
|
12707
12820
|
}
|
|
12708
12821
|
}
|
|
12709
|
-
function injectDestroyRef() {
|
|
12710
|
-
return new NodeInjectorDestroyRef(getLView());
|
|
12711
|
-
}
|
|
12712
|
-
|
|
12713
12822
|
/**
|
|
12714
|
-
*
|
|
12823
|
+
* Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
|
|
12824
|
+
* them by executing an associated template function.
|
|
12715
12825
|
*/
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
12723
|
-
|
|
12724
|
-
if (!this.all.has(watch)) {
|
|
12725
|
-
return;
|
|
12826
|
+
function refreshEmbeddedViews(lView) {
|
|
12827
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12828
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12829
|
+
const embeddedLView = lContainer[i];
|
|
12830
|
+
const embeddedTView = embeddedLView[TVIEW];
|
|
12831
|
+
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12832
|
+
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12833
|
+
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12726
12834
|
}
|
|
12727
|
-
this.queue.set(watch, zone);
|
|
12728
|
-
}, allowSignalWrites);
|
|
12729
|
-
this.all.add(watch);
|
|
12730
|
-
// Effects start dirty.
|
|
12731
|
-
watch.notify();
|
|
12732
|
-
let unregisterOnDestroy;
|
|
12733
|
-
const destroy = () => {
|
|
12734
|
-
watch.cleanup();
|
|
12735
|
-
unregisterOnDestroy?.();
|
|
12736
|
-
this.all.delete(watch);
|
|
12737
|
-
this.queue.delete(watch);
|
|
12738
|
-
};
|
|
12739
|
-
unregisterOnDestroy = destroyRef?.onDestroy(destroy);
|
|
12740
|
-
return {
|
|
12741
|
-
destroy,
|
|
12742
|
-
};
|
|
12743
|
-
}
|
|
12744
|
-
flush() {
|
|
12745
|
-
if (this.queue.size === 0) {
|
|
12746
|
-
return;
|
|
12747
|
-
}
|
|
12748
|
-
for (const [watch, zone] of this.queue) {
|
|
12749
|
-
this.queue.delete(watch);
|
|
12750
|
-
zone.run(() => watch.run());
|
|
12751
12835
|
}
|
|
12752
12836
|
}
|
|
12753
|
-
get isQueueEmpty() {
|
|
12754
|
-
return this.queue.size === 0;
|
|
12755
|
-
}
|
|
12756
|
-
/** @nocollapse */
|
|
12757
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
12758
|
-
token: EffectManager,
|
|
12759
|
-
providedIn: 'root',
|
|
12760
|
-
factory: () => new EffectManager(),
|
|
12761
|
-
}); }
|
|
12762
12837
|
}
|
|
12763
12838
|
/**
|
|
12764
|
-
*
|
|
12839
|
+
* Mark transplanted views as needing to be refreshed at their insertion points.
|
|
12765
12840
|
*
|
|
12766
|
-
* @
|
|
12841
|
+
* @param lView The `LView` that may have transplanted views.
|
|
12767
12842
|
*/
|
|
12768
|
-
function
|
|
12769
|
-
|
|
12770
|
-
|
|
12771
|
-
|
|
12772
|
-
|
|
12773
|
-
|
|
12843
|
+
function markTransplantedViewsForRefresh(lView) {
|
|
12844
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12845
|
+
if (!lContainer[HAS_TRANSPLANTED_VIEWS])
|
|
12846
|
+
continue;
|
|
12847
|
+
const movedViews = lContainer[MOVED_VIEWS];
|
|
12848
|
+
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
|
|
12849
|
+
for (let i = 0; i < movedViews.length; i++) {
|
|
12850
|
+
const movedLView = movedViews[i];
|
|
12851
|
+
const insertionLContainer = movedLView[PARENT];
|
|
12852
|
+
ngDevMode && assertLContainer(insertionLContainer);
|
|
12853
|
+
markViewForRefresh(movedLView);
|
|
12854
|
+
}
|
|
12855
|
+
}
|
|
12774
12856
|
}
|
|
12775
|
-
|
|
12776
12857
|
/**
|
|
12777
|
-
*
|
|
12778
|
-
*
|
|
12779
|
-
* This function should be called during `firstCreatePass` only.
|
|
12858
|
+
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12780
12859
|
*
|
|
12781
|
-
* @param
|
|
12782
|
-
* @param attrs `TAttributes` containing the styling information.
|
|
12783
|
-
* @param writeToHost Where should the resulting static styles be written?
|
|
12784
|
-
* - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
|
|
12785
|
-
* - `true` Write to `TNode.styles` / `TNode.classes`
|
|
12860
|
+
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12786
12861
|
*/
|
|
12787
|
-
function
|
|
12788
|
-
ngDevMode &&
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
else if (mode == 1 /* AttributeMarker.Classes */) {
|
|
12800
|
-
classes = concatStringsWithSpace(classes, value);
|
|
12801
|
-
}
|
|
12802
|
-
else if (mode == 2 /* AttributeMarker.Styles */) {
|
|
12803
|
-
const style = value;
|
|
12804
|
-
const styleValue = attrs[++i];
|
|
12805
|
-
styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
|
|
12806
|
-
}
|
|
12862
|
+
function refreshComponent(hostLView, componentHostIdx) {
|
|
12863
|
+
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12864
|
+
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12865
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12866
|
+
if (viewAttachedToChangeDetector(componentView)) {
|
|
12867
|
+
const tView = componentView[TVIEW];
|
|
12868
|
+
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12869
|
+
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12870
|
+
}
|
|
12871
|
+
else if (componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12872
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12873
|
+
refreshContainsDirtyView(componentView);
|
|
12807
12874
|
}
|
|
12808
12875
|
}
|
|
12809
|
-
writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
|
|
12810
|
-
writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
|
|
12811
12876
|
}
|
|
12812
|
-
|
|
12813
|
-
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
|
|
12821
|
-
|
|
12822
|
-
|
|
12823
|
-
|
|
12824
|
-
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
12828
|
-
if (
|
|
12829
|
-
|
|
12877
|
+
/**
|
|
12878
|
+
* Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
|
|
12879
|
+
* children or descendants of the given lView.
|
|
12880
|
+
*
|
|
12881
|
+
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12882
|
+
*/
|
|
12883
|
+
function refreshContainsDirtyView(lView) {
|
|
12884
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12885
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12886
|
+
const embeddedLView = lContainer[i];
|
|
12887
|
+
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12888
|
+
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
|
|
12889
|
+
const embeddedTView = embeddedLView[TVIEW];
|
|
12890
|
+
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12891
|
+
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12892
|
+
}
|
|
12893
|
+
else if (embeddedLView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12894
|
+
refreshContainsDirtyView(embeddedLView);
|
|
12830
12895
|
}
|
|
12831
12896
|
}
|
|
12832
12897
|
}
|
|
12833
|
-
|
|
12834
|
-
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
12843
|
-
|
|
12844
|
-
else if (tNodeType & 16 /* TNodeType.Projection */) {
|
|
12845
|
-
const nodesInSlot = getProjectionNodes(lView, tNode);
|
|
12846
|
-
if (Array.isArray(nodesInSlot)) {
|
|
12847
|
-
result.push(...nodesInSlot);
|
|
12848
|
-
}
|
|
12849
|
-
else {
|
|
12850
|
-
const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
|
|
12851
|
-
ngDevMode && assertParentView(parentView);
|
|
12852
|
-
collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
|
|
12898
|
+
}
|
|
12899
|
+
const tView = lView[TVIEW];
|
|
12900
|
+
// Refresh child component views.
|
|
12901
|
+
const components = tView.components;
|
|
12902
|
+
if (components !== null) {
|
|
12903
|
+
for (let i = 0; i < components.length; i++) {
|
|
12904
|
+
const componentView = getComponentLViewByIndex(components[i], lView);
|
|
12905
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12906
|
+
if (viewAttachedToChangeDetector(componentView) &&
|
|
12907
|
+
componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12908
|
+
refreshContainsDirtyView(componentView);
|
|
12853
12909
|
}
|
|
12854
12910
|
}
|
|
12855
|
-
tNode = isProjection ? tNode.projectionNext : tNode.next;
|
|
12856
12911
|
}
|
|
12857
|
-
|
|
12912
|
+
}
|
|
12913
|
+
/** Refreshes child components in the current view (update mode). */
|
|
12914
|
+
function refreshChildComponents(hostLView, components) {
|
|
12915
|
+
for (let i = 0; i < components.length; i++) {
|
|
12916
|
+
refreshComponent(hostLView, components[i]);
|
|
12917
|
+
}
|
|
12858
12918
|
}
|
|
12859
12919
|
|
|
12860
12920
|
class ViewRef {
|
|
@@ -14539,18 +14599,6 @@ function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
|
|
|
14539
14599
|
return ɵɵattributeInterpolateV;
|
|
14540
14600
|
}
|
|
14541
14601
|
|
|
14542
|
-
/**
|
|
14543
|
-
* Synchronously perform change detection on a component (and possibly its sub-components).
|
|
14544
|
-
*
|
|
14545
|
-
* This function triggers change detection in a synchronous way on a component.
|
|
14546
|
-
*
|
|
14547
|
-
* @param component The component which the change detection should be performed on.
|
|
14548
|
-
*/
|
|
14549
|
-
function detectChanges(component) {
|
|
14550
|
-
const view = getComponentViewByInstance(component);
|
|
14551
|
-
detectChangesInternal(view[TVIEW], view, component);
|
|
14552
|
-
}
|
|
14553
|
-
|
|
14554
14602
|
const AT_THIS_LOCATION = '<-- AT THIS LOCATION';
|
|
14555
14603
|
/**
|
|
14556
14604
|
* Retrieves a user friendly string for a given TNodeType for use in
|
|
@@ -14624,9 +14672,16 @@ function validateSiblingNodeExists(node) {
|
|
|
14624
14672
|
/**
|
|
14625
14673
|
* Validates that a node exists or throws
|
|
14626
14674
|
*/
|
|
14627
|
-
function validateNodeExists(node) {
|
|
14675
|
+
function validateNodeExists(node, lView = null, tNode = null) {
|
|
14628
14676
|
if (!node) {
|
|
14629
|
-
|
|
14677
|
+
const header = 'During hydration, Angular expected an element to be present at this location.\n\n';
|
|
14678
|
+
let expected = '';
|
|
14679
|
+
let footer = '';
|
|
14680
|
+
if (lView !== null && tNode !== null) {
|
|
14681
|
+
expected = `${describeExpectedDom(lView, tNode, false)}\n\n`;
|
|
14682
|
+
footer = getHydrationErrorFooter();
|
|
14683
|
+
}
|
|
14684
|
+
throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + expected + footer);
|
|
14630
14685
|
}
|
|
14631
14686
|
}
|
|
14632
14687
|
/**
|
|
@@ -14683,7 +14738,7 @@ function invalidSkipHydrationHost(rNode) {
|
|
|
14683
14738
|
'that doesn\'t act as a component host. Hydration can be ' +
|
|
14684
14739
|
'skipped only on per-component basis.\n\n';
|
|
14685
14740
|
const actual = `${describeDomFromNode(rNode)}\n\n`;
|
|
14686
|
-
const footer = 'Please move the `ngSkipHydration` attribute to the component host element
|
|
14741
|
+
const footer = 'Please move the `ngSkipHydration` attribute to the component host element.\n\n';
|
|
14687
14742
|
const message = header + actual + footer;
|
|
14688
14743
|
return new RuntimeError(-504 /* RuntimeErrorCode.INVALID_SKIP_HYDRATION_HOST */, message);
|
|
14689
14744
|
}
|
|
@@ -14868,8 +14923,9 @@ function getHydrationErrorFooter(componentClassName) {
|
|
|
14868
14923
|
const componentInfo = componentClassName ? `the "${componentClassName}"` : 'corresponding';
|
|
14869
14924
|
return `To fix this problem:\n` +
|
|
14870
14925
|
` * check ${componentInfo} component for hydration-related issues\n` +
|
|
14926
|
+
` * check to see if your template has valid HTML structure\n` +
|
|
14871
14927
|
` * or skip hydration by adding the \`ngSkipHydration\` attribute ` +
|
|
14872
|
-
`to its host node in a template`;
|
|
14928
|
+
`to its host node in a template\n\n`;
|
|
14873
14929
|
}
|
|
14874
14930
|
/**
|
|
14875
14931
|
* An attribute related note for hydration errors
|
|
@@ -15096,10 +15152,10 @@ function locateRNodeByPath(path, lView) {
|
|
|
15096
15152
|
const [referenceNode, ...navigationInstructions] = decompressNodeLocation(path);
|
|
15097
15153
|
let ref;
|
|
15098
15154
|
if (referenceNode === REFERENCE_NODE_HOST) {
|
|
15099
|
-
ref = lView[
|
|
15155
|
+
ref = lView[DECLARATION_COMPONENT_VIEW][HOST];
|
|
15100
15156
|
}
|
|
15101
15157
|
else if (referenceNode === REFERENCE_NODE_BODY) {
|
|
15102
|
-
ref = ɵɵresolveBody(lView[
|
|
15158
|
+
ref = ɵɵresolveBody(lView[DECLARATION_COMPONENT_VIEW][HOST]);
|
|
15103
15159
|
}
|
|
15104
15160
|
else {
|
|
15105
15161
|
const parentElementId = Number(referenceNode);
|
|
@@ -15143,6 +15199,7 @@ function navigateBetween(start, finish) {
|
|
|
15143
15199
|
}
|
|
15144
15200
|
/**
|
|
15145
15201
|
* Calculates a path between 2 sibling nodes (generates a number of `NextSibling` navigations).
|
|
15202
|
+
* Returns `null` if no such path exists between the given nodes.
|
|
15146
15203
|
*/
|
|
15147
15204
|
function navigateBetweenSiblings(start, finish) {
|
|
15148
15205
|
const nav = [];
|
|
@@ -15150,7 +15207,10 @@ function navigateBetweenSiblings(start, finish) {
|
|
|
15150
15207
|
for (node = start; node != null && node !== finish; node = node.nextSibling) {
|
|
15151
15208
|
nav.push(NodeNavigationStep.NextSibling);
|
|
15152
15209
|
}
|
|
15153
|
-
|
|
15210
|
+
// If the `node` becomes `null` or `undefined` at the end, that means that we
|
|
15211
|
+
// didn't find the `end` node, thus return `null` (which would trigger serialization
|
|
15212
|
+
// error to be produced).
|
|
15213
|
+
return node == null ? null : nav;
|
|
15154
15214
|
}
|
|
15155
15215
|
/**
|
|
15156
15216
|
* Calculates a path between 2 nodes in terms of `nextSibling` and `firstChild`
|
|
@@ -15173,10 +15233,11 @@ function calcPathForNode(tNode, lView) {
|
|
|
15173
15233
|
let parentIndex;
|
|
15174
15234
|
let parentRNode;
|
|
15175
15235
|
let referenceNodeName;
|
|
15176
|
-
if (parentTNode === null) {
|
|
15177
|
-
//
|
|
15236
|
+
if (parentTNode === null || !(parentTNode.type & 3 /* TNodeType.AnyRNode */)) {
|
|
15237
|
+
// If there is no parent TNode or a parent TNode does not represent an RNode
|
|
15238
|
+
// (i.e. not a DOM node), use component host element as a reference node.
|
|
15178
15239
|
parentIndex = referenceNodeName = REFERENCE_NODE_HOST;
|
|
15179
|
-
parentRNode = lView[HOST];
|
|
15240
|
+
parentRNode = lView[DECLARATION_COMPONENT_VIEW][HOST];
|
|
15180
15241
|
}
|
|
15181
15242
|
else {
|
|
15182
15243
|
// Use parent TNode as a reference node.
|
|
@@ -15224,17 +15285,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
|
|
|
15224
15285
|
ngDevMode && assertFirstCreatePass(tView);
|
|
15225
15286
|
ngDevMode && ngDevMode.firstCreatePass++;
|
|
15226
15287
|
const tViewConsts = tView.consts;
|
|
15227
|
-
let ssrId = null;
|
|
15228
|
-
const hydrationInfo = lView[HYDRATION];
|
|
15229
|
-
if (hydrationInfo) {
|
|
15230
|
-
const noOffsetIndex = index - HEADER_OFFSET;
|
|
15231
|
-
ssrId = (hydrationInfo && hydrationInfo.data[TEMPLATES]?.[noOffsetIndex]) ?? null;
|
|
15232
|
-
}
|
|
15233
15288
|
// TODO(pk): refactor getOrCreateTNode to have the "create" only version
|
|
15234
15289
|
const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
|
|
15235
15290
|
resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
|
|
15236
15291
|
registerPostOrderHooks(tView, tNode);
|
|
15237
|
-
const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, ssrId);
|
|
15292
|
+
const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */);
|
|
15238
15293
|
if (tView.queries !== null) {
|
|
15239
15294
|
tView.queries.template(tView, tNode);
|
|
15240
15295
|
embeddedTView.queries = tView.queries.embeddedTView(tNode);
|
|
@@ -15301,9 +15356,27 @@ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
|
|
|
15301
15356
|
if (isNodeCreationMode) {
|
|
15302
15357
|
return createContainerAnchorImpl(tView, lView, tNode, index);
|
|
15303
15358
|
}
|
|
15359
|
+
const ssrId = hydrationInfo.data[TEMPLATES]?.[index] ?? null;
|
|
15360
|
+
// Apply `ssrId` value to the underlying TView if it was not previously set.
|
|
15361
|
+
//
|
|
15362
|
+
// There might be situations when the same component is present in a template
|
|
15363
|
+
// multiple times and some instances are opted-out of using hydration via
|
|
15364
|
+
// `ngSkipHydration` attribute. In this scenario, at the time a TView is created,
|
|
15365
|
+
// the `ssrId` might be `null` (if the first component is opted-out of hydration).
|
|
15366
|
+
// The code below makes sure that the `ssrId` is applied to the TView if it's still
|
|
15367
|
+
// `null` and verifies we never try to override it with a different value.
|
|
15368
|
+
if (ssrId !== null && tNode.tView !== null) {
|
|
15369
|
+
if (tNode.tView.ssrId === null) {
|
|
15370
|
+
tNode.tView.ssrId = ssrId;
|
|
15371
|
+
}
|
|
15372
|
+
else {
|
|
15373
|
+
ngDevMode &&
|
|
15374
|
+
assertEqual(tNode.tView.ssrId, ssrId, 'Unexpected value of the `ssrId` for this TView');
|
|
15375
|
+
}
|
|
15376
|
+
}
|
|
15304
15377
|
// Hydration mode, looking up existing elements in DOM.
|
|
15305
15378
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
15306
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15379
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
15307
15380
|
setSegmentHead(hydrationInfo, index, currentRNode);
|
|
15308
15381
|
const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
|
|
15309
15382
|
const comment = siblingAfter(viewContainerSize, currentRNode);
|
|
@@ -15537,7 +15610,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
|
|
|
15537
15610
|
// `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
|
|
15538
15611
|
// so while processing a `<div>` instruction, point to the next sibling as a
|
|
15539
15612
|
// start of a segment.
|
|
15540
|
-
ngDevMode && validateNodeExists(native.nextSibling);
|
|
15613
|
+
ngDevMode && validateNodeExists(native.nextSibling, lView, tNode);
|
|
15541
15614
|
setSegmentHead(hydrationInfo, index, native.nextSibling);
|
|
15542
15615
|
}
|
|
15543
15616
|
// Checks if the skip hydration attribute is present during hydration so we know to
|
|
@@ -15682,7 +15755,7 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
|
|
|
15682
15755
|
}
|
|
15683
15756
|
// Hydration mode, looking up existing elements in DOM.
|
|
15684
15757
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
15685
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15758
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
15686
15759
|
const ngContainerSize = getNgContainerSize(hydrationInfo, index);
|
|
15687
15760
|
ngDevMode &&
|
|
15688
15761
|
assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
|
|
@@ -17345,7 +17418,7 @@ function styleStringParser(keyValueArray, text) {
|
|
|
17345
17418
|
* @codeGenApi
|
|
17346
17419
|
*/
|
|
17347
17420
|
function ɵɵclassMap(classes) {
|
|
17348
|
-
checkStylingMap(
|
|
17421
|
+
checkStylingMap(classKeyValueArraySet, classStringParser, classes, true);
|
|
17349
17422
|
}
|
|
17350
17423
|
/**
|
|
17351
17424
|
* Parse text as class and add values to KeyValueArray.
|
|
@@ -17787,6 +17860,26 @@ function toStylingKeyValueArray(keyValueArraySet, stringParser, value) {
|
|
|
17787
17860
|
function styleKeyValueArraySet(keyValueArray, key, value) {
|
|
17788
17861
|
keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
|
|
17789
17862
|
}
|
|
17863
|
+
/**
|
|
17864
|
+
* Class-binding-specific function for setting the `value` for a `key`.
|
|
17865
|
+
*
|
|
17866
|
+
* See: `keyValueArraySet` for details
|
|
17867
|
+
*
|
|
17868
|
+
* @param keyValueArray KeyValueArray to add to.
|
|
17869
|
+
* @param key Style key to add.
|
|
17870
|
+
* @param value The value to set.
|
|
17871
|
+
*/
|
|
17872
|
+
function classKeyValueArraySet(keyValueArray, key, value) {
|
|
17873
|
+
// We use `classList.add` to eventually add the CSS classes to the DOM node. Any value passed into
|
|
17874
|
+
// `add` is stringified and added to the `class` attribute, e.g. even null, undefined or numbers
|
|
17875
|
+
// will be added. Stringify the key here so that our internal data structure matches the value in
|
|
17876
|
+
// the DOM. The only exceptions are empty strings and strings that contain spaces for which
|
|
17877
|
+
// the browser throws an error. We ignore such values, because the error is somewhat cryptic.
|
|
17878
|
+
const stringKey = String(key);
|
|
17879
|
+
if (stringKey !== '' && !stringKey.includes(' ')) {
|
|
17880
|
+
keyValueArraySet(keyValueArray, stringKey, value);
|
|
17881
|
+
}
|
|
17882
|
+
}
|
|
17790
17883
|
/**
|
|
17791
17884
|
* Update map based styling.
|
|
17792
17885
|
*
|
|
@@ -20516,11 +20609,10 @@ const MARKER = `�`;
|
|
|
20516
20609
|
const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
|
|
20517
20610
|
const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi;
|
|
20518
20611
|
/**
|
|
20519
|
-
* Angular
|
|
20520
|
-
*
|
|
20521
|
-
*
|
|
20522
|
-
*
|
|
20523
|
-
* might contain this special character.
|
|
20612
|
+
* Angular uses the special entity &ngsp; as a placeholder for non-removable space.
|
|
20613
|
+
* It's replaced by the 0xE500 PUA (Private Use Areas) unicode character and later on replaced by a
|
|
20614
|
+
* space.
|
|
20615
|
+
* We are re-implementing the same idea since translations might contain this special character.
|
|
20524
20616
|
*/
|
|
20525
20617
|
const NGSP_UNICODE_REGEXP = /\uE500/g;
|
|
20526
20618
|
function replaceNgsp(value) {
|
|
@@ -25663,12 +25755,7 @@ class TestBedCompiler {
|
|
|
25663
25755
|
if (this.compilerProviders !== null) {
|
|
25664
25756
|
providers.push(...this.compilerProviders);
|
|
25665
25757
|
}
|
|
25666
|
-
|
|
25667
|
-
class CompilerModule {
|
|
25668
|
-
}
|
|
25669
|
-
ɵcompileNgModuleDefs(CompilerModule, { providers });
|
|
25670
|
-
const CompilerModuleFactory = new ɵNgModuleFactory(CompilerModule);
|
|
25671
|
-
this._injector = CompilerModuleFactory.create(this.platform.injector).injector;
|
|
25758
|
+
this._injector = Injector$1.create({ providers, parent: this.platform.injector });
|
|
25672
25759
|
return this._injector;
|
|
25673
25760
|
}
|
|
25674
25761
|
// get overrides for a specific provider (if any)
|
|
@@ -26138,9 +26225,7 @@ class TestBedImpl {
|
|
|
26138
26225
|
if (!componentDef) {
|
|
26139
26226
|
throw new Error(`It looks like '${ɵstringify(type)}' has not been compiled.`);
|
|
26140
26227
|
}
|
|
26141
|
-
// TODO: Don't cast as `InjectionToken<boolean>`, proper type is boolean[]
|
|
26142
26228
|
const noNgZone = this.inject(ComponentFixtureNoNgZone, false);
|
|
26143
|
-
// TODO: Don't cast as `InjectionToken<boolean>`, proper type is boolean[]
|
|
26144
26229
|
const autoDetect = this.inject(ComponentFixtureAutoDetect, false);
|
|
26145
26230
|
const ngZone = noNgZone ? null : this.inject(NgZone, null);
|
|
26146
26231
|
const componentFactory = new ɵRender3ComponentFactory(componentDef);
|