@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/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
|
*/
|
|
@@ -156,9 +156,9 @@ function formatRuntimeError(code, message) {
|
|
|
156
156
|
// generate a link to the error details page on angular.io.
|
|
157
157
|
// We also prepend `0` to non-compile-time errors.
|
|
158
158
|
const fullCode = `NG0${Math.abs(code)}`;
|
|
159
|
-
let errorMessage = `${fullCode}${message ? ': ' + message
|
|
159
|
+
let errorMessage = `${fullCode}${message ? ': ' + message : ''}`;
|
|
160
160
|
if (ngDevMode && code < 0) {
|
|
161
|
-
const addPeriodSeparator = !errorMessage.match(/[
|
|
161
|
+
const addPeriodSeparator = !errorMessage.match(/[.,;!?\n]$/);
|
|
162
162
|
const separator = addPeriodSeparator ? '.' : '';
|
|
163
163
|
errorMessage =
|
|
164
164
|
`${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
|
|
@@ -1920,10 +1920,8 @@ function getComponentId(componentDef) {
|
|
|
1920
1920
|
if (GENERATED_COMP_IDS.has(compId)) {
|
|
1921
1921
|
const previousCompDefType = GENERATED_COMP_IDS.get(compId);
|
|
1922
1922
|
if (previousCompDefType !== componentDef.type) {
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
console.warn(`Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
|
|
1926
|
-
.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.`);
|
|
1923
|
+
console.warn(formatRuntimeError(-912 /* RuntimeErrorCode.COMPONENT_ID_COLLISION */, `Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
|
|
1924
|
+
.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.`));
|
|
1927
1925
|
}
|
|
1928
1926
|
}
|
|
1929
1927
|
else {
|
|
@@ -1941,7 +1939,7 @@ const TVIEW = 1;
|
|
|
1941
1939
|
const FLAGS = 2;
|
|
1942
1940
|
const PARENT = 3;
|
|
1943
1941
|
const NEXT = 4;
|
|
1944
|
-
const
|
|
1942
|
+
const DESCENDANT_VIEWS_TO_REFRESH = 5;
|
|
1945
1943
|
const T_HOST = 6;
|
|
1946
1944
|
const CLEANUP = 7;
|
|
1947
1945
|
const CONTEXT = 8;
|
|
@@ -1994,7 +1992,7 @@ const TYPE = 1;
|
|
|
1994
1992
|
* that the `MOVED_VIEWS` are transplanted and on-push.
|
|
1995
1993
|
*/
|
|
1996
1994
|
const HAS_TRANSPLANTED_VIEWS = 2;
|
|
1997
|
-
// PARENT, NEXT,
|
|
1995
|
+
// PARENT, NEXT, DESCENDANT_VIEWS_TO_REFRESH are indices 3, 4, and 5
|
|
1998
1996
|
// As we already have these constants in LView, we don't need to re-create them.
|
|
1999
1997
|
// T_HOST is index 6
|
|
2000
1998
|
// We already have this constants in LView, we don't need to re-create it.
|
|
@@ -2996,20 +2994,44 @@ function resetPreOrderHookFlags(lView) {
|
|
|
2996
2994
|
lView[PREORDER_HOOK_FLAGS] = 0;
|
|
2997
2995
|
}
|
|
2998
2996
|
/**
|
|
2999
|
-
*
|
|
3000
|
-
*
|
|
2997
|
+
* Adds the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
|
|
2998
|
+
* parents.
|
|
2999
|
+
*/
|
|
3000
|
+
function markViewForRefresh(lView) {
|
|
3001
|
+
if ((lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) === 0) {
|
|
3002
|
+
lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
3003
|
+
updateViewsToRefresh(lView, 1);
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
/**
|
|
3007
|
+
* Removes the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
|
|
3008
|
+
* parents.
|
|
3009
|
+
*/
|
|
3010
|
+
function clearViewRefreshFlag(lView) {
|
|
3011
|
+
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
|
|
3012
|
+
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshView */;
|
|
3013
|
+
updateViewsToRefresh(lView, -1);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
/**
|
|
3017
|
+
* Updates the `DESCENDANT_VIEWS_TO_REFRESH` counter on the parents of the `LView` as well as the
|
|
3018
|
+
* parents above that whose
|
|
3001
3019
|
* 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
|
|
3002
3020
|
* or
|
|
3003
3021
|
* 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
|
|
3004
3022
|
*/
|
|
3005
|
-
function
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3023
|
+
function updateViewsToRefresh(lView, amount) {
|
|
3024
|
+
let parent = lView[PARENT];
|
|
3025
|
+
if (parent === null) {
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
|
|
3029
|
+
let viewOrContainer = parent;
|
|
3030
|
+
parent = parent[PARENT];
|
|
3009
3031
|
while (parent !== null &&
|
|
3010
|
-
((amount === 1 && viewOrContainer[
|
|
3011
|
-
(amount === -1 && viewOrContainer[
|
|
3012
|
-
parent[
|
|
3032
|
+
((amount === 1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 1) ||
|
|
3033
|
+
(amount === -1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 0))) {
|
|
3034
|
+
parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
|
|
3013
3035
|
viewOrContainer = parent;
|
|
3014
3036
|
parent = parent[PARENT];
|
|
3015
3037
|
}
|
|
@@ -6853,12 +6875,8 @@ function detachMovedView(declarationContainer, lView) {
|
|
|
6853
6875
|
const insertionLContainer = lView[PARENT];
|
|
6854
6876
|
ngDevMode && assertLContainer(insertionLContainer);
|
|
6855
6877
|
// If the view was marked for refresh but then detached before it was checked (where the flag
|
|
6856
|
-
// would be cleared and the counter decremented), we need to
|
|
6857
|
-
|
|
6858
|
-
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
6859
|
-
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
|
|
6860
|
-
updateTransplantedViewCount(insertionLContainer, -1);
|
|
6861
|
-
}
|
|
6878
|
+
// would be cleared and the counter decremented), we need to update the status here.
|
|
6879
|
+
clearViewRefreshFlag(lView);
|
|
6862
6880
|
movedViews.splice(declarationViewIndex, 1);
|
|
6863
6881
|
}
|
|
6864
6882
|
/**
|
|
@@ -9963,7 +9981,7 @@ class Version {
|
|
|
9963
9981
|
/**
|
|
9964
9982
|
* @publicApi
|
|
9965
9983
|
*/
|
|
9966
|
-
const VERSION = new Version('16.0.0-rc.
|
|
9984
|
+
const VERSION = new Version('16.0.0-rc.3');
|
|
9967
9985
|
|
|
9968
9986
|
// This default value is when checking the hierarchy for a token.
|
|
9969
9987
|
//
|
|
@@ -10111,12 +10129,11 @@ function isInSkipHydrationBlock(tNode) {
|
|
|
10111
10129
|
return false;
|
|
10112
10130
|
}
|
|
10113
10131
|
|
|
10114
|
-
const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
10115
10132
|
/**
|
|
10116
10133
|
* Internal token that specifies whether DOM reuse logic
|
|
10117
10134
|
* during hydration is enabled.
|
|
10118
10135
|
*/
|
|
10119
|
-
const IS_HYDRATION_DOM_REUSE_ENABLED = new InjectionToken(
|
|
10136
|
+
const IS_HYDRATION_DOM_REUSE_ENABLED = new InjectionToken((typeof ngDevMode === 'undefined' || !!ngDevMode) ? 'IS_HYDRATION_DOM_REUSE_ENABLED' : '');
|
|
10120
10137
|
// By default (in client rendering mode), we remove all the contents
|
|
10121
10138
|
// of the host element and render an application after that.
|
|
10122
10139
|
const PRESERVE_HOST_CONTENT_DEFAULT = false;
|
|
@@ -10124,7 +10141,7 @@ const PRESERVE_HOST_CONTENT_DEFAULT = false;
|
|
|
10124
10141
|
* Internal token that indicates whether host element content should be
|
|
10125
10142
|
* retained during the bootstrap.
|
|
10126
10143
|
*/
|
|
10127
|
-
const PRESERVE_HOST_CONTENT = new InjectionToken(
|
|
10144
|
+
const PRESERVE_HOST_CONTENT = new InjectionToken((typeof ngDevMode === 'undefined' || !!ngDevMode) ? 'PRESERVE_HOST_CONTENT' : '', {
|
|
10128
10145
|
providedIn: 'root',
|
|
10129
10146
|
factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
|
|
10130
10147
|
});
|
|
@@ -10282,7 +10299,6 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
|
|
|
10282
10299
|
return { propName: undefined, oldValue, newValue };
|
|
10283
10300
|
}
|
|
10284
10301
|
|
|
10285
|
-
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;
|
|
10286
10302
|
class ReactiveLViewConsumer extends ReactiveNode {
|
|
10287
10303
|
constructor() {
|
|
10288
10304
|
super(...arguments);
|
|
@@ -10290,11 +10306,12 @@ class ReactiveLViewConsumer extends ReactiveNode {
|
|
|
10290
10306
|
this._lView = null;
|
|
10291
10307
|
}
|
|
10292
10308
|
set lView(lView) {
|
|
10293
|
-
|
|
10309
|
+
(typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
10310
|
+
assertEqual(this._lView, null, 'Consumer already associated with a view.');
|
|
10294
10311
|
this._lView = lView;
|
|
10295
10312
|
}
|
|
10296
10313
|
onConsumerDependencyMayHaveChanged() {
|
|
10297
|
-
|
|
10314
|
+
(typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
10298
10315
|
assertDefined(this._lView, 'Updating a signal during template or host binding execution is not allowed.');
|
|
10299
10316
|
markViewDirty(this._lView);
|
|
10300
10317
|
}
|
|
@@ -10712,39 +10729,10 @@ function processHostBindingOpCodes(tView, lView) {
|
|
|
10712
10729
|
}
|
|
10713
10730
|
}
|
|
10714
10731
|
finally {
|
|
10715
|
-
lView[REACTIVE_HOST_BINDING_CONSUMER] === null
|
|
10732
|
+
if (lView[REACTIVE_HOST_BINDING_CONSUMER] === null) {
|
|
10716
10733
|
commitLViewConsumerIfHasProducers(lView, REACTIVE_HOST_BINDING_CONSUMER);
|
|
10717
|
-
setSelectedIndex(-1);
|
|
10718
|
-
}
|
|
10719
|
-
}
|
|
10720
|
-
/** Refreshes all content queries declared by directives in a given view */
|
|
10721
|
-
function refreshContentQueries(tView, lView) {
|
|
10722
|
-
const contentQueries = tView.contentQueries;
|
|
10723
|
-
if (contentQueries !== null) {
|
|
10724
|
-
for (let i = 0; i < contentQueries.length; i += 2) {
|
|
10725
|
-
const queryStartIdx = contentQueries[i];
|
|
10726
|
-
const directiveDefIdx = contentQueries[i + 1];
|
|
10727
|
-
if (directiveDefIdx !== -1) {
|
|
10728
|
-
const directiveDef = tView.data[directiveDefIdx];
|
|
10729
|
-
ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
|
|
10730
|
-
ngDevMode &&
|
|
10731
|
-
assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
|
|
10732
|
-
setCurrentQueryIndex(queryStartIdx);
|
|
10733
|
-
directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
|
|
10734
|
-
}
|
|
10735
10734
|
}
|
|
10736
|
-
|
|
10737
|
-
}
|
|
10738
|
-
/** Refreshes child components in the current view (update mode). */
|
|
10739
|
-
function refreshChildComponents(hostLView, components) {
|
|
10740
|
-
for (let i = 0; i < components.length; i++) {
|
|
10741
|
-
refreshComponent(hostLView, components[i]);
|
|
10742
|
-
}
|
|
10743
|
-
}
|
|
10744
|
-
/** Renders child components in the current view (creation mode). */
|
|
10745
|
-
function renderChildComponents(hostLView, components) {
|
|
10746
|
-
for (let i = 0; i < components.length; i++) {
|
|
10747
|
-
renderComponent(hostLView, components[i]);
|
|
10735
|
+
setSelectedIndex(-1);
|
|
10748
10736
|
}
|
|
10749
10737
|
}
|
|
10750
10738
|
function createLView(parentLView, tView, context, flags, host, tHostNode, environment, renderer, injector, embeddedViewInjector, hydrationInfo) {
|
|
@@ -10768,7 +10756,6 @@ function createLView(parentLView, tView, context, flags, host, tHostNode, enviro
|
|
|
10768
10756
|
lView[ID] = getUniqueLViewId();
|
|
10769
10757
|
lView[HYDRATION] = hydrationInfo;
|
|
10770
10758
|
lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
|
|
10771
|
-
lView[REACTIVE_TEMPLATE_CONSUMER] = null;
|
|
10772
10759
|
ngDevMode &&
|
|
10773
10760
|
assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
|
|
10774
10761
|
lView[DECLARATION_COMPONENT_VIEW] =
|
|
@@ -10864,195 +10851,6 @@ function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
|
|
|
10864
10851
|
}
|
|
10865
10852
|
return allocIdx;
|
|
10866
10853
|
}
|
|
10867
|
-
//////////////////////////
|
|
10868
|
-
//// Render
|
|
10869
|
-
//////////////////////////
|
|
10870
|
-
/**
|
|
10871
|
-
* Processes a view in the creation mode. This includes a number of steps in a specific order:
|
|
10872
|
-
* - creating view query functions (if any);
|
|
10873
|
-
* - executing a template function in the creation mode;
|
|
10874
|
-
* - updating static queries (if any);
|
|
10875
|
-
* - creating child components defined in a given view.
|
|
10876
|
-
*/
|
|
10877
|
-
function renderView(tView, lView, context) {
|
|
10878
|
-
ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
|
|
10879
|
-
enterView(lView);
|
|
10880
|
-
try {
|
|
10881
|
-
const viewQuery = tView.viewQuery;
|
|
10882
|
-
if (viewQuery !== null) {
|
|
10883
|
-
executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
|
|
10884
|
-
}
|
|
10885
|
-
// Execute a template associated with this view, if it exists. A template function might not be
|
|
10886
|
-
// defined for the root component views.
|
|
10887
|
-
const templateFn = tView.template;
|
|
10888
|
-
if (templateFn !== null) {
|
|
10889
|
-
executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
|
|
10890
|
-
}
|
|
10891
|
-
// This needs to be set before children are processed to support recursive components.
|
|
10892
|
-
// This must be set to false immediately after the first creation run because in an
|
|
10893
|
-
// ngFor loop, all the views will be created together before update mode runs and turns
|
|
10894
|
-
// off firstCreatePass. If we don't set it here, instances will perform directive
|
|
10895
|
-
// matching, etc again and again.
|
|
10896
|
-
if (tView.firstCreatePass) {
|
|
10897
|
-
tView.firstCreatePass = false;
|
|
10898
|
-
}
|
|
10899
|
-
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
|
10900
|
-
// content queries are resolved during change detection (i.e. update mode), after embedded
|
|
10901
|
-
// views are refreshed (see block above).
|
|
10902
|
-
if (tView.staticContentQueries) {
|
|
10903
|
-
refreshContentQueries(tView, lView);
|
|
10904
|
-
}
|
|
10905
|
-
// We must materialize query results before child components are processed
|
|
10906
|
-
// in case a child component has projected a container. The LContainer needs
|
|
10907
|
-
// to exist so the embedded views are properly attached by the container.
|
|
10908
|
-
if (tView.staticViewQueries) {
|
|
10909
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
|
|
10910
|
-
}
|
|
10911
|
-
// Render child component views.
|
|
10912
|
-
const components = tView.components;
|
|
10913
|
-
if (components !== null) {
|
|
10914
|
-
renderChildComponents(lView, components);
|
|
10915
|
-
}
|
|
10916
|
-
}
|
|
10917
|
-
catch (error) {
|
|
10918
|
-
// If we didn't manage to get past the first template pass due to
|
|
10919
|
-
// an error, mark the view as corrupted so we can try to recover.
|
|
10920
|
-
if (tView.firstCreatePass) {
|
|
10921
|
-
tView.incompleteFirstPass = true;
|
|
10922
|
-
tView.firstCreatePass = false;
|
|
10923
|
-
}
|
|
10924
|
-
throw error;
|
|
10925
|
-
}
|
|
10926
|
-
finally {
|
|
10927
|
-
lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
|
|
10928
|
-
leaveView();
|
|
10929
|
-
}
|
|
10930
|
-
}
|
|
10931
|
-
/**
|
|
10932
|
-
* Processes a view in update mode. This includes a number of steps in a specific order:
|
|
10933
|
-
* - executing a template function in update mode;
|
|
10934
|
-
* - executing hooks;
|
|
10935
|
-
* - refreshing queries;
|
|
10936
|
-
* - setting host bindings;
|
|
10937
|
-
* - refreshing child (embedded and component) views.
|
|
10938
|
-
*/
|
|
10939
|
-
function refreshView(tView, lView, templateFn, context) {
|
|
10940
|
-
ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
|
|
10941
|
-
const flags = lView[FLAGS];
|
|
10942
|
-
if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
|
|
10943
|
-
return;
|
|
10944
|
-
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
10945
|
-
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
|
10946
|
-
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
10947
|
-
!isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
|
|
10948
|
-
enterView(lView);
|
|
10949
|
-
try {
|
|
10950
|
-
resetPreOrderHookFlags(lView);
|
|
10951
|
-
setBindingIndex(tView.bindingStartIndex);
|
|
10952
|
-
if (templateFn !== null) {
|
|
10953
|
-
executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
|
|
10954
|
-
}
|
|
10955
|
-
const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
|
|
10956
|
-
// execute pre-order hooks (OnInit, OnChanges, DoCheck)
|
|
10957
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
10958
|
-
if (!isInCheckNoChangesPass) {
|
|
10959
|
-
if (hooksInitPhaseCompleted) {
|
|
10960
|
-
const preOrderCheckHooks = tView.preOrderCheckHooks;
|
|
10961
|
-
if (preOrderCheckHooks !== null) {
|
|
10962
|
-
executeCheckHooks(lView, preOrderCheckHooks, null);
|
|
10963
|
-
}
|
|
10964
|
-
}
|
|
10965
|
-
else {
|
|
10966
|
-
const preOrderHooks = tView.preOrderHooks;
|
|
10967
|
-
if (preOrderHooks !== null) {
|
|
10968
|
-
executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
|
|
10969
|
-
}
|
|
10970
|
-
incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
|
|
10971
|
-
}
|
|
10972
|
-
}
|
|
10973
|
-
// First mark transplanted views that are declared in this lView as needing a refresh at their
|
|
10974
|
-
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
10975
|
-
// `LView` but its declaration appears after the insertion component.
|
|
10976
|
-
markTransplantedViewsForRefresh(lView);
|
|
10977
|
-
refreshEmbeddedViews(lView);
|
|
10978
|
-
// Content query results must be refreshed before content hooks are called.
|
|
10979
|
-
if (tView.contentQueries !== null) {
|
|
10980
|
-
refreshContentQueries(tView, lView);
|
|
10981
|
-
}
|
|
10982
|
-
// execute content hooks (AfterContentInit, AfterContentChecked)
|
|
10983
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
10984
|
-
if (!isInCheckNoChangesPass) {
|
|
10985
|
-
if (hooksInitPhaseCompleted) {
|
|
10986
|
-
const contentCheckHooks = tView.contentCheckHooks;
|
|
10987
|
-
if (contentCheckHooks !== null) {
|
|
10988
|
-
executeCheckHooks(lView, contentCheckHooks);
|
|
10989
|
-
}
|
|
10990
|
-
}
|
|
10991
|
-
else {
|
|
10992
|
-
const contentHooks = tView.contentHooks;
|
|
10993
|
-
if (contentHooks !== null) {
|
|
10994
|
-
executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
10995
|
-
}
|
|
10996
|
-
incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
10997
|
-
}
|
|
10998
|
-
}
|
|
10999
|
-
processHostBindingOpCodes(tView, lView);
|
|
11000
|
-
// Refresh child component views.
|
|
11001
|
-
const components = tView.components;
|
|
11002
|
-
if (components !== null) {
|
|
11003
|
-
refreshChildComponents(lView, components);
|
|
11004
|
-
}
|
|
11005
|
-
// View queries must execute after refreshing child components because a template in this view
|
|
11006
|
-
// could be inserted in a child component. If the view query executes before child component
|
|
11007
|
-
// refresh, the template might not yet be inserted.
|
|
11008
|
-
const viewQuery = tView.viewQuery;
|
|
11009
|
-
if (viewQuery !== null) {
|
|
11010
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
|
|
11011
|
-
}
|
|
11012
|
-
// execute view hooks (AfterViewInit, AfterViewChecked)
|
|
11013
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
11014
|
-
if (!isInCheckNoChangesPass) {
|
|
11015
|
-
if (hooksInitPhaseCompleted) {
|
|
11016
|
-
const viewCheckHooks = tView.viewCheckHooks;
|
|
11017
|
-
if (viewCheckHooks !== null) {
|
|
11018
|
-
executeCheckHooks(lView, viewCheckHooks);
|
|
11019
|
-
}
|
|
11020
|
-
}
|
|
11021
|
-
else {
|
|
11022
|
-
const viewHooks = tView.viewHooks;
|
|
11023
|
-
if (viewHooks !== null) {
|
|
11024
|
-
executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11025
|
-
}
|
|
11026
|
-
incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11027
|
-
}
|
|
11028
|
-
}
|
|
11029
|
-
if (tView.firstUpdatePass === true) {
|
|
11030
|
-
// We need to make sure that we only flip the flag on successful `refreshView` only
|
|
11031
|
-
// Don't do this in `finally` block.
|
|
11032
|
-
// If we did this in `finally` block then an exception could block the execution of styling
|
|
11033
|
-
// instructions which in turn would be unable to insert themselves into the styling linked
|
|
11034
|
-
// list. The result of this would be that if the exception would not be throw on subsequent CD
|
|
11035
|
-
// the styling would be unable to process it data and reflect to the DOM.
|
|
11036
|
-
tView.firstUpdatePass = false;
|
|
11037
|
-
}
|
|
11038
|
-
// Do not reset the dirty state when running in check no changes mode. We don't want components
|
|
11039
|
-
// to behave differently depending on whether check no changes is enabled or not. For example:
|
|
11040
|
-
// Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
|
|
11041
|
-
// refresh a `NgClass` binding should work. If we would reset the dirty state in the check
|
|
11042
|
-
// no changes cycle, the component would be not be dirty for the next update pass. This would
|
|
11043
|
-
// be different in production mode where the component dirty state is not reset.
|
|
11044
|
-
if (!isInCheckNoChangesPass) {
|
|
11045
|
-
lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
|
|
11046
|
-
}
|
|
11047
|
-
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
11048
|
-
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
|
|
11049
|
-
updateTransplantedViewCount(lView[PARENT], -1);
|
|
11050
|
-
}
|
|
11051
|
-
}
|
|
11052
|
-
finally {
|
|
11053
|
-
leaveView();
|
|
11054
|
-
}
|
|
11055
|
-
}
|
|
11056
10854
|
function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
11057
10855
|
const consumer = getReactiveLViewConsumer(lView, REACTIVE_TEMPLATE_CONSUMER);
|
|
11058
10856
|
const prevSelectedIndex = getSelectedIndex();
|
|
@@ -11066,10 +10864,21 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
|
11066
10864
|
}
|
|
11067
10865
|
const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
|
|
11068
10866
|
profiler(preHookType, context);
|
|
11069
|
-
|
|
10867
|
+
if (isUpdatePhase) {
|
|
10868
|
+
consumer.runInContext(templateFn, rf, context);
|
|
10869
|
+
}
|
|
10870
|
+
else {
|
|
10871
|
+
const prevConsumer = setActiveConsumer(null);
|
|
10872
|
+
try {
|
|
10873
|
+
templateFn(rf, context);
|
|
10874
|
+
}
|
|
10875
|
+
finally {
|
|
10876
|
+
setActiveConsumer(prevConsumer);
|
|
10877
|
+
}
|
|
10878
|
+
}
|
|
11070
10879
|
}
|
|
11071
10880
|
finally {
|
|
11072
|
-
if (lView[REACTIVE_TEMPLATE_CONSUMER] === null) {
|
|
10881
|
+
if (isUpdatePhase && lView[REACTIVE_TEMPLATE_CONSUMER] === null) {
|
|
11073
10882
|
commitLViewConsumerIfHasProducers(lView, REACTIVE_TEMPLATE_CONSUMER);
|
|
11074
10883
|
}
|
|
11075
10884
|
setSelectedIndex(prevSelectedIndex);
|
|
@@ -11082,14 +10891,20 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
|
11082
10891
|
//////////////////////////
|
|
11083
10892
|
function executeContentQueries(tView, tNode, lView) {
|
|
11084
10893
|
if (isContentQueryHost(tNode)) {
|
|
11085
|
-
const
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
const
|
|
11089
|
-
|
|
11090
|
-
def
|
|
10894
|
+
const prevConsumer = setActiveConsumer(null);
|
|
10895
|
+
try {
|
|
10896
|
+
const start = tNode.directiveStart;
|
|
10897
|
+
const end = tNode.directiveEnd;
|
|
10898
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
10899
|
+
const def = tView.data[directiveIndex];
|
|
10900
|
+
if (def.contentQueries) {
|
|
10901
|
+
def.contentQueries(1 /* RenderFlags.Create */, lView[directiveIndex], directiveIndex);
|
|
10902
|
+
}
|
|
11091
10903
|
}
|
|
11092
10904
|
}
|
|
10905
|
+
finally {
|
|
10906
|
+
setActiveConsumer(prevConsumer);
|
|
10907
|
+
}
|
|
11093
10908
|
}
|
|
11094
10909
|
}
|
|
11095
10910
|
/**
|
|
@@ -11908,17 +11723,11 @@ function setElementAttribute(renderer, element, namespace, tagName, name, value,
|
|
|
11908
11723
|
function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
|
|
11909
11724
|
const initialInputs = initialInputData[directiveIndex];
|
|
11910
11725
|
if (initialInputs !== null) {
|
|
11911
|
-
const setInput = def.setInput;
|
|
11912
11726
|
for (let i = 0; i < initialInputs.length;) {
|
|
11913
11727
|
const publicName = initialInputs[i++];
|
|
11914
11728
|
const privateName = initialInputs[i++];
|
|
11915
11729
|
const value = initialInputs[i++];
|
|
11916
|
-
|
|
11917
|
-
def.setInput(instance, value, publicName, privateName);
|
|
11918
|
-
}
|
|
11919
|
-
else {
|
|
11920
|
-
instance[privateName] = value;
|
|
11921
|
-
}
|
|
11730
|
+
writeToDirectiveInput(def, instance, publicName, privateName, value);
|
|
11922
11731
|
if (ngDevMode) {
|
|
11923
11732
|
const nativeElement = getNativeByTNode(tNode, lView);
|
|
11924
11733
|
setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
|
|
@@ -11926,6 +11735,20 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
|
|
|
11926
11735
|
}
|
|
11927
11736
|
}
|
|
11928
11737
|
}
|
|
11738
|
+
function writeToDirectiveInput(def, instance, publicName, privateName, value) {
|
|
11739
|
+
const prevConsumer = setActiveConsumer(null);
|
|
11740
|
+
try {
|
|
11741
|
+
if (def.setInput !== null) {
|
|
11742
|
+
def.setInput(instance, value, publicName, privateName);
|
|
11743
|
+
}
|
|
11744
|
+
else {
|
|
11745
|
+
instance[privateName] = value;
|
|
11746
|
+
}
|
|
11747
|
+
}
|
|
11748
|
+
finally {
|
|
11749
|
+
setActiveConsumer(prevConsumer);
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11929
11752
|
/**
|
|
11930
11753
|
* Generates initialInputData for a node and stores it in the template's static storage
|
|
11931
11754
|
* so subsequent template invocations don't have to recalculate it.
|
|
@@ -12010,151 +11833,24 @@ function createLContainer(hostNative, currentView, native, tNode) {
|
|
|
12010
11833
|
assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
|
|
12011
11834
|
return lContainer;
|
|
12012
11835
|
}
|
|
12013
|
-
/**
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
}
|
|
12028
|
-
}
|
|
12029
|
-
/**
|
|
12030
|
-
* Mark transplanted views as needing to be refreshed at their insertion points.
|
|
12031
|
-
*
|
|
12032
|
-
* @param lView The `LView` that may have transplanted views.
|
|
12033
|
-
*/
|
|
12034
|
-
function markTransplantedViewsForRefresh(lView) {
|
|
12035
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12036
|
-
if (!lContainer[HAS_TRANSPLANTED_VIEWS])
|
|
12037
|
-
continue;
|
|
12038
|
-
const movedViews = lContainer[MOVED_VIEWS];
|
|
12039
|
-
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
|
|
12040
|
-
for (let i = 0; i < movedViews.length; i++) {
|
|
12041
|
-
const movedLView = movedViews[i];
|
|
12042
|
-
const insertionLContainer = movedLView[PARENT];
|
|
12043
|
-
ngDevMode && assertLContainer(insertionLContainer);
|
|
12044
|
-
// We don't want to increment the counter if the moved LView was already marked for
|
|
12045
|
-
// refresh.
|
|
12046
|
-
if ((movedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) === 0) {
|
|
12047
|
-
updateTransplantedViewCount(insertionLContainer, 1);
|
|
12048
|
-
}
|
|
12049
|
-
// Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
|
|
12050
|
-
// those that aren't (declaration component === insertion component). In the latter case,
|
|
12051
|
-
// it's fine to add the flag, as we will clear it immediately in
|
|
12052
|
-
// `refreshEmbeddedViews` for the view currently being refreshed.
|
|
12053
|
-
movedLView[FLAGS] |= 1024 /* LViewFlags.RefreshTransplantedView */;
|
|
12054
|
-
}
|
|
12055
|
-
}
|
|
12056
|
-
}
|
|
12057
|
-
/////////////
|
|
12058
|
-
/**
|
|
12059
|
-
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12060
|
-
*
|
|
12061
|
-
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12062
|
-
*/
|
|
12063
|
-
function refreshComponent(hostLView, componentHostIdx) {
|
|
12064
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12065
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12066
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12067
|
-
if (viewAttachedToChangeDetector(componentView)) {
|
|
12068
|
-
const tView = componentView[TVIEW];
|
|
12069
|
-
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12070
|
-
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12071
|
-
}
|
|
12072
|
-
else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12073
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12074
|
-
refreshContainsDirtyView(componentView);
|
|
12075
|
-
}
|
|
12076
|
-
}
|
|
12077
|
-
}
|
|
12078
|
-
/**
|
|
12079
|
-
* Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
|
|
12080
|
-
* children or descendants of the given lView.
|
|
12081
|
-
*
|
|
12082
|
-
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12083
|
-
*/
|
|
12084
|
-
function refreshContainsDirtyView(lView) {
|
|
12085
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12086
|
-
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12087
|
-
const embeddedLView = lContainer[i];
|
|
12088
|
-
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12089
|
-
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
12090
|
-
const embeddedTView = embeddedLView[TVIEW];
|
|
12091
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12092
|
-
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12093
|
-
}
|
|
12094
|
-
else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12095
|
-
refreshContainsDirtyView(embeddedLView);
|
|
12096
|
-
}
|
|
12097
|
-
}
|
|
12098
|
-
}
|
|
12099
|
-
}
|
|
12100
|
-
const tView = lView[TVIEW];
|
|
12101
|
-
// Refresh child component views.
|
|
12102
|
-
const components = tView.components;
|
|
12103
|
-
if (components !== null) {
|
|
12104
|
-
for (let i = 0; i < components.length; i++) {
|
|
12105
|
-
const componentView = getComponentLViewByIndex(components[i], lView);
|
|
12106
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12107
|
-
if (viewAttachedToChangeDetector(componentView) &&
|
|
12108
|
-
componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12109
|
-
refreshContainsDirtyView(componentView);
|
|
11836
|
+
/** Refreshes all content queries declared by directives in a given view */
|
|
11837
|
+
function refreshContentQueries(tView, lView) {
|
|
11838
|
+
const contentQueries = tView.contentQueries;
|
|
11839
|
+
if (contentQueries !== null) {
|
|
11840
|
+
for (let i = 0; i < contentQueries.length; i += 2) {
|
|
11841
|
+
const queryStartIdx = contentQueries[i];
|
|
11842
|
+
const directiveDefIdx = contentQueries[i + 1];
|
|
11843
|
+
if (directiveDefIdx !== -1) {
|
|
11844
|
+
const directiveDef = tView.data[directiveDefIdx];
|
|
11845
|
+
ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
|
|
11846
|
+
ngDevMode &&
|
|
11847
|
+
assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
|
|
11848
|
+
setCurrentQueryIndex(queryStartIdx);
|
|
11849
|
+
directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
|
|
12110
11850
|
}
|
|
12111
11851
|
}
|
|
12112
11852
|
}
|
|
12113
11853
|
}
|
|
12114
|
-
function renderComponent(hostLView, componentHostIdx) {
|
|
12115
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
|
|
12116
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12117
|
-
const componentTView = componentView[TVIEW];
|
|
12118
|
-
syncViewWithBlueprint(componentTView, componentView);
|
|
12119
|
-
const hostRNode = componentView[HOST];
|
|
12120
|
-
// Populate an LView with hydration info retrieved from the DOM via TransferState.
|
|
12121
|
-
if (hostRNode !== null && componentView[HYDRATION] === null) {
|
|
12122
|
-
componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
|
|
12123
|
-
}
|
|
12124
|
-
renderView(componentTView, componentView, componentView[CONTEXT]);
|
|
12125
|
-
}
|
|
12126
|
-
/**
|
|
12127
|
-
* Syncs an LView instance with its blueprint if they have gotten out of sync.
|
|
12128
|
-
*
|
|
12129
|
-
* Typically, blueprints and their view instances should always be in sync, so the loop here
|
|
12130
|
-
* will be skipped. However, consider this case of two components side-by-side:
|
|
12131
|
-
*
|
|
12132
|
-
* App template:
|
|
12133
|
-
* ```
|
|
12134
|
-
* <comp></comp>
|
|
12135
|
-
* <comp></comp>
|
|
12136
|
-
* ```
|
|
12137
|
-
*
|
|
12138
|
-
* The following will happen:
|
|
12139
|
-
* 1. App template begins processing.
|
|
12140
|
-
* 2. First <comp> is matched as a component and its LView is created.
|
|
12141
|
-
* 3. Second <comp> is matched as a component and its LView is created.
|
|
12142
|
-
* 4. App template completes processing, so it's time to check child templates.
|
|
12143
|
-
* 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
|
|
12144
|
-
* 6. Second <comp> template is checked. Its blueprint has been updated by the first
|
|
12145
|
-
* <comp> template, but its LView was created before this update, so it is out of sync.
|
|
12146
|
-
*
|
|
12147
|
-
* Note that embedded views inside ngFor loops will never be out of sync because these views
|
|
12148
|
-
* are processed as soon as they are created.
|
|
12149
|
-
*
|
|
12150
|
-
* @param tView The `TView` that contains the blueprint for syncing
|
|
12151
|
-
* @param lView The view to sync
|
|
12152
|
-
*/
|
|
12153
|
-
function syncViewWithBlueprint(tView, lView) {
|
|
12154
|
-
for (let i = lView.length; i < tView.blueprint.length; i++) {
|
|
12155
|
-
lView.push(tView.blueprint[i]);
|
|
12156
|
-
}
|
|
12157
|
-
}
|
|
12158
11854
|
/**
|
|
12159
11855
|
* Adds LView or LContainer to the end of the current view tree.
|
|
12160
11856
|
*
|
|
@@ -12183,45 +11879,17 @@ function addToViewTree(lView, lViewOrLContainer) {
|
|
|
12183
11879
|
///////////////////////////////
|
|
12184
11880
|
//// Change detection
|
|
12185
11881
|
///////////////////////////////
|
|
12186
|
-
function
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
// to avoid any possible side-effects.
|
|
12191
|
-
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
|
12192
|
-
if (!checkNoChangesMode && rendererFactory.begin)
|
|
12193
|
-
rendererFactory.begin();
|
|
12194
|
-
try {
|
|
12195
|
-
refreshView(tView, lView, tView.template, context);
|
|
12196
|
-
}
|
|
12197
|
-
catch (error) {
|
|
12198
|
-
if (notifyErrorHandler) {
|
|
12199
|
-
handleError(lView, error);
|
|
12200
|
-
}
|
|
12201
|
-
throw error;
|
|
12202
|
-
}
|
|
12203
|
-
finally {
|
|
12204
|
-
if (!checkNoChangesMode && rendererFactory.end)
|
|
12205
|
-
rendererFactory.end();
|
|
12206
|
-
// One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
|
|
12207
|
-
// other post-order hooks.
|
|
12208
|
-
!checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
|
|
12209
|
-
}
|
|
12210
|
-
}
|
|
12211
|
-
function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12212
|
-
setIsInCheckNoChangesMode(true);
|
|
11882
|
+
function executeViewQueryFn(flags, viewQueryFn, component) {
|
|
11883
|
+
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
|
|
11884
|
+
setCurrentQueryIndex(0);
|
|
11885
|
+
const prevConsumer = setActiveConsumer(null);
|
|
12213
11886
|
try {
|
|
12214
|
-
|
|
11887
|
+
viewQueryFn(flags, component);
|
|
12215
11888
|
}
|
|
12216
11889
|
finally {
|
|
12217
|
-
|
|
11890
|
+
setActiveConsumer(prevConsumer);
|
|
12218
11891
|
}
|
|
12219
11892
|
}
|
|
12220
|
-
function executeViewQueryFn(flags, viewQueryFn, component) {
|
|
12221
|
-
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
|
|
12222
|
-
setCurrentQueryIndex(0);
|
|
12223
|
-
viewQueryFn(flags, component);
|
|
12224
|
-
}
|
|
12225
11893
|
///////////////////////////////
|
|
12226
11894
|
//// Bindings & interpolations
|
|
12227
11895
|
///////////////////////////////
|
|
@@ -12308,12 +11976,7 @@ function setInputsForProperty(tView, lView, inputs, publicName, value) {
|
|
|
12308
11976
|
const instance = lView[index];
|
|
12309
11977
|
ngDevMode && assertIndexInRange(lView, index);
|
|
12310
11978
|
const def = tView.data[index];
|
|
12311
|
-
|
|
12312
|
-
def.setInput(instance, value, publicName, privateName);
|
|
12313
|
-
}
|
|
12314
|
-
else {
|
|
12315
|
-
instance[privateName] = value;
|
|
12316
|
-
}
|
|
11979
|
+
writeToDirectiveInput(def, instance, publicName, privateName, value);
|
|
12317
11980
|
}
|
|
12318
11981
|
}
|
|
12319
11982
|
/**
|
|
@@ -12328,185 +11991,582 @@ function textBindingInternal(lView, index, value) {
|
|
|
12328
11991
|
updateTextNode(lView[RENDERER], element, value);
|
|
12329
11992
|
}
|
|
12330
11993
|
|
|
11994
|
+
function renderComponent(hostLView, componentHostIdx) {
|
|
11995
|
+
ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
|
|
11996
|
+
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
11997
|
+
const componentTView = componentView[TVIEW];
|
|
11998
|
+
syncViewWithBlueprint(componentTView, componentView);
|
|
11999
|
+
const hostRNode = componentView[HOST];
|
|
12000
|
+
// Populate an LView with hydration info retrieved from the DOM via TransferState.
|
|
12001
|
+
if (hostRNode !== null && componentView[HYDRATION] === null) {
|
|
12002
|
+
componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
|
|
12003
|
+
}
|
|
12004
|
+
renderView(componentTView, componentView, componentView[CONTEXT]);
|
|
12005
|
+
}
|
|
12331
12006
|
/**
|
|
12332
|
-
*
|
|
12333
|
-
* The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
|
|
12334
|
-
* is injected in a component or directive, the callbacks run when that component or
|
|
12335
|
-
* directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
|
|
12007
|
+
* Syncs an LView instance with its blueprint if they have gotten out of sync.
|
|
12336
12008
|
*
|
|
12337
|
-
*
|
|
12009
|
+
* Typically, blueprints and their view instances should always be in sync, so the loop here
|
|
12010
|
+
* will be skipped. However, consider this case of two components side-by-side:
|
|
12011
|
+
*
|
|
12012
|
+
* App template:
|
|
12013
|
+
* ```
|
|
12014
|
+
* <comp></comp>
|
|
12015
|
+
* <comp></comp>
|
|
12016
|
+
* ```
|
|
12017
|
+
*
|
|
12018
|
+
* The following will happen:
|
|
12019
|
+
* 1. App template begins processing.
|
|
12020
|
+
* 2. First <comp> is matched as a component and its LView is created.
|
|
12021
|
+
* 3. Second <comp> is matched as a component and its LView is created.
|
|
12022
|
+
* 4. App template completes processing, so it's time to check child templates.
|
|
12023
|
+
* 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
|
|
12024
|
+
* 6. Second <comp> template is checked. Its blueprint has been updated by the first
|
|
12025
|
+
* <comp> template, but its LView was created before this update, so it is out of sync.
|
|
12026
|
+
*
|
|
12027
|
+
* Note that embedded views inside ngFor loops will never be out of sync because these views
|
|
12028
|
+
* are processed as soon as they are created.
|
|
12029
|
+
*
|
|
12030
|
+
* @param tView The `TView` that contains the blueprint for syncing
|
|
12031
|
+
* @param lView The view to sync
|
|
12338
12032
|
*/
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
*/
|
|
12344
|
-
static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
|
|
12345
|
-
/**
|
|
12346
|
-
* @internal
|
|
12347
|
-
* @nocollapse
|
|
12348
|
-
*/
|
|
12349
|
-
static { this.__NG_ENV_ID__ = (injector) => injector; }
|
|
12033
|
+
function syncViewWithBlueprint(tView, lView) {
|
|
12034
|
+
for (let i = lView.length; i < tView.blueprint.length; i++) {
|
|
12035
|
+
lView.push(tView.blueprint[i]);
|
|
12036
|
+
}
|
|
12350
12037
|
}
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12038
|
+
/**
|
|
12039
|
+
* Processes a view in the creation mode. This includes a number of steps in a specific order:
|
|
12040
|
+
* - creating view query functions (if any);
|
|
12041
|
+
* - executing a template function in the creation mode;
|
|
12042
|
+
* - updating static queries (if any);
|
|
12043
|
+
* - creating child components defined in a given view.
|
|
12044
|
+
*/
|
|
12045
|
+
function renderView(tView, lView, context) {
|
|
12046
|
+
ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
|
|
12047
|
+
enterView(lView);
|
|
12048
|
+
try {
|
|
12049
|
+
const viewQuery = tView.viewQuery;
|
|
12050
|
+
if (viewQuery !== null) {
|
|
12051
|
+
executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
|
|
12052
|
+
}
|
|
12053
|
+
// Execute a template associated with this view, if it exists. A template function might not be
|
|
12054
|
+
// defined for the root component views.
|
|
12055
|
+
const templateFn = tView.template;
|
|
12056
|
+
if (templateFn !== null) {
|
|
12057
|
+
executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
|
|
12058
|
+
}
|
|
12059
|
+
// This needs to be set before children are processed to support recursive components.
|
|
12060
|
+
// This must be set to false immediately after the first creation run because in an
|
|
12061
|
+
// ngFor loop, all the views will be created together before update mode runs and turns
|
|
12062
|
+
// off firstCreatePass. If we don't set it here, instances will perform directive
|
|
12063
|
+
// matching, etc again and again.
|
|
12064
|
+
if (tView.firstCreatePass) {
|
|
12065
|
+
tView.firstCreatePass = false;
|
|
12066
|
+
}
|
|
12067
|
+
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
|
12068
|
+
// content queries are resolved during change detection (i.e. update mode), after embedded
|
|
12069
|
+
// views are refreshed (see block above).
|
|
12070
|
+
if (tView.staticContentQueries) {
|
|
12071
|
+
refreshContentQueries(tView, lView);
|
|
12072
|
+
}
|
|
12073
|
+
// We must materialize query results before child components are processed
|
|
12074
|
+
// in case a child component has projected a container. The LContainer needs
|
|
12075
|
+
// to exist so the embedded views are properly attached by the container.
|
|
12076
|
+
if (tView.staticViewQueries) {
|
|
12077
|
+
executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
|
|
12078
|
+
}
|
|
12079
|
+
// Render child component views.
|
|
12080
|
+
const components = tView.components;
|
|
12081
|
+
if (components !== null) {
|
|
12082
|
+
renderChildComponents(lView, components);
|
|
12083
|
+
}
|
|
12084
|
+
}
|
|
12085
|
+
catch (error) {
|
|
12086
|
+
// If we didn't manage to get past the first template pass due to
|
|
12087
|
+
// an error, mark the view as corrupted so we can try to recover.
|
|
12088
|
+
if (tView.firstCreatePass) {
|
|
12089
|
+
tView.incompleteFirstPass = true;
|
|
12090
|
+
tView.firstCreatePass = false;
|
|
12091
|
+
}
|
|
12092
|
+
throw error;
|
|
12093
|
+
}
|
|
12094
|
+
finally {
|
|
12095
|
+
lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
|
|
12096
|
+
leaveView();
|
|
12097
|
+
}
|
|
12098
|
+
}
|
|
12099
|
+
/** Renders child components in the current view (creation mode). */
|
|
12100
|
+
function renderChildComponents(hostLView, components) {
|
|
12101
|
+
for (let i = 0; i < components.length; i++) {
|
|
12102
|
+
renderComponent(hostLView, components[i]);
|
|
12103
|
+
}
|
|
12104
|
+
}
|
|
12105
|
+
|
|
12106
|
+
/**
|
|
12107
|
+
* `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
|
|
12108
|
+
* The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
|
|
12109
|
+
* is injected in a component or directive, the callbacks run when that component or
|
|
12110
|
+
* directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
|
|
12111
|
+
*
|
|
12112
|
+
* @publicApi
|
|
12113
|
+
*/
|
|
12114
|
+
class DestroyRef {
|
|
12115
|
+
/**
|
|
12116
|
+
* @internal
|
|
12117
|
+
* @nocollapse
|
|
12118
|
+
*/
|
|
12119
|
+
static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
|
|
12120
|
+
/**
|
|
12121
|
+
* @internal
|
|
12122
|
+
* @nocollapse
|
|
12123
|
+
*/
|
|
12124
|
+
static { this.__NG_ENV_ID__ = (injector) => injector; }
|
|
12125
|
+
}
|
|
12126
|
+
class NodeInjectorDestroyRef extends DestroyRef {
|
|
12127
|
+
constructor(_lView) {
|
|
12128
|
+
super();
|
|
12129
|
+
this._lView = _lView;
|
|
12130
|
+
}
|
|
12131
|
+
onDestroy(callback) {
|
|
12132
|
+
storeLViewOnDestroy(this._lView, callback);
|
|
12133
|
+
return () => removeLViewOnDestroy(this._lView, callback);
|
|
12134
|
+
}
|
|
12135
|
+
}
|
|
12136
|
+
function injectDestroyRef() {
|
|
12137
|
+
return new NodeInjectorDestroyRef(getLView());
|
|
12138
|
+
}
|
|
12139
|
+
|
|
12140
|
+
/**
|
|
12141
|
+
* Tracks all effects registered within a given application and runs them via `flush`.
|
|
12142
|
+
*/
|
|
12143
|
+
class EffectManager {
|
|
12144
|
+
constructor() {
|
|
12145
|
+
this.all = new Set();
|
|
12146
|
+
this.queue = new Map();
|
|
12147
|
+
}
|
|
12148
|
+
create(effectFn, destroyRef, allowSignalWrites) {
|
|
12149
|
+
const zone = (typeof Zone === 'undefined') ? null : Zone.current;
|
|
12150
|
+
const watch = new Watch(effectFn, (watch) => {
|
|
12151
|
+
if (!this.all.has(watch)) {
|
|
12152
|
+
return;
|
|
12153
|
+
}
|
|
12154
|
+
this.queue.set(watch, zone);
|
|
12155
|
+
}, allowSignalWrites);
|
|
12156
|
+
this.all.add(watch);
|
|
12157
|
+
// Effects start dirty.
|
|
12158
|
+
watch.notify();
|
|
12159
|
+
let unregisterOnDestroy;
|
|
12160
|
+
const destroy = () => {
|
|
12161
|
+
watch.cleanup();
|
|
12162
|
+
unregisterOnDestroy?.();
|
|
12163
|
+
this.all.delete(watch);
|
|
12164
|
+
this.queue.delete(watch);
|
|
12165
|
+
};
|
|
12166
|
+
unregisterOnDestroy = destroyRef?.onDestroy(destroy);
|
|
12167
|
+
return {
|
|
12168
|
+
destroy,
|
|
12169
|
+
};
|
|
12170
|
+
}
|
|
12171
|
+
flush() {
|
|
12172
|
+
if (this.queue.size === 0) {
|
|
12173
|
+
return;
|
|
12174
|
+
}
|
|
12175
|
+
for (const [watch, zone] of this.queue) {
|
|
12176
|
+
this.queue.delete(watch);
|
|
12177
|
+
if (zone) {
|
|
12178
|
+
zone.run(() => watch.run());
|
|
12179
|
+
}
|
|
12180
|
+
else {
|
|
12181
|
+
watch.run();
|
|
12182
|
+
}
|
|
12183
|
+
}
|
|
12184
|
+
}
|
|
12185
|
+
get isQueueEmpty() {
|
|
12186
|
+
return this.queue.size === 0;
|
|
12187
|
+
}
|
|
12188
|
+
/** @nocollapse */
|
|
12189
|
+
static { this.ɵprov = ɵɵdefineInjectable({
|
|
12190
|
+
token: EffectManager,
|
|
12191
|
+
providedIn: 'root',
|
|
12192
|
+
factory: () => new EffectManager(),
|
|
12193
|
+
}); }
|
|
12194
|
+
}
|
|
12195
|
+
/**
|
|
12196
|
+
* Create a global `Effect` for the given reactive function.
|
|
12197
|
+
*
|
|
12198
|
+
* @developerPreview
|
|
12199
|
+
*/
|
|
12200
|
+
function effect(effectFn, options) {
|
|
12201
|
+
!options?.injector && assertInInjectionContext(effect);
|
|
12202
|
+
const injector = options?.injector ?? inject(Injector);
|
|
12203
|
+
const effectManager = injector.get(EffectManager);
|
|
12204
|
+
const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
|
|
12205
|
+
return effectManager.create(effectFn, destroyRef, !!options?.allowSignalWrites);
|
|
12206
|
+
}
|
|
12207
|
+
|
|
12208
|
+
/**
|
|
12209
|
+
* Compute the static styling (class/style) from `TAttributes`.
|
|
12210
|
+
*
|
|
12211
|
+
* This function should be called during `firstCreatePass` only.
|
|
12212
|
+
*
|
|
12213
|
+
* @param tNode The `TNode` into which the styling information should be loaded.
|
|
12214
|
+
* @param attrs `TAttributes` containing the styling information.
|
|
12215
|
+
* @param writeToHost Where should the resulting static styles be written?
|
|
12216
|
+
* - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
|
|
12217
|
+
* - `true` Write to `TNode.styles` / `TNode.classes`
|
|
12218
|
+
*/
|
|
12219
|
+
function computeStaticStyling(tNode, attrs, writeToHost) {
|
|
12220
|
+
ngDevMode &&
|
|
12221
|
+
assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
|
|
12222
|
+
let styles = writeToHost ? tNode.styles : null;
|
|
12223
|
+
let classes = writeToHost ? tNode.classes : null;
|
|
12224
|
+
let mode = 0;
|
|
12225
|
+
if (attrs !== null) {
|
|
12226
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
12227
|
+
const value = attrs[i];
|
|
12228
|
+
if (typeof value === 'number') {
|
|
12229
|
+
mode = value;
|
|
12230
|
+
}
|
|
12231
|
+
else if (mode == 1 /* AttributeMarker.Classes */) {
|
|
12232
|
+
classes = concatStringsWithSpace(classes, value);
|
|
12233
|
+
}
|
|
12234
|
+
else if (mode == 2 /* AttributeMarker.Styles */) {
|
|
12235
|
+
const style = value;
|
|
12236
|
+
const styleValue = attrs[++i];
|
|
12237
|
+
styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
|
|
12238
|
+
}
|
|
12239
|
+
}
|
|
12240
|
+
}
|
|
12241
|
+
writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
|
|
12242
|
+
writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
|
|
12243
|
+
}
|
|
12244
|
+
|
|
12245
|
+
function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
|
|
12246
|
+
while (tNode !== null) {
|
|
12247
|
+
ngDevMode &&
|
|
12248
|
+
assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
|
|
12249
|
+
const lNode = lView[tNode.index];
|
|
12250
|
+
if (lNode !== null) {
|
|
12251
|
+
result.push(unwrapRNode(lNode));
|
|
12252
|
+
}
|
|
12253
|
+
// A given lNode can represent either a native node or a LContainer (when it is a host of a
|
|
12254
|
+
// ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
|
|
12255
|
+
// from the views in this container.
|
|
12256
|
+
if (isLContainer(lNode)) {
|
|
12257
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
|
|
12258
|
+
const lViewInAContainer = lNode[i];
|
|
12259
|
+
const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
|
|
12260
|
+
if (lViewFirstChildTNode !== null) {
|
|
12261
|
+
collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
|
|
12262
|
+
}
|
|
12263
|
+
}
|
|
12264
|
+
// When an LContainer is created, the anchor (comment) node is:
|
|
12265
|
+
// - (1) either reused in case of an ElementContainer (<ng-container>)
|
|
12266
|
+
// - (2) or a new comment node is created
|
|
12267
|
+
// In the first case, the anchor comment node would be added to the final
|
|
12268
|
+
// list by the code above (`result.push(unwrapRNode(lNode))`), but the second
|
|
12269
|
+
// case requires extra handling: the anchor node needs to be added to the
|
|
12270
|
+
// final list manually. See additional information in the `createAnchorNode`
|
|
12271
|
+
// function in the `view_container_ref.ts`.
|
|
12272
|
+
//
|
|
12273
|
+
// In the first case, the same reference would be stored in the `NATIVE`
|
|
12274
|
+
// and `HOST` slots in an LContainer. Otherwise, this is the second case and
|
|
12275
|
+
// we should add an element to the final list.
|
|
12276
|
+
if (lNode[NATIVE] !== lNode[HOST]) {
|
|
12277
|
+
result.push(lNode[NATIVE]);
|
|
12278
|
+
}
|
|
12279
|
+
}
|
|
12280
|
+
const tNodeType = tNode.type;
|
|
12281
|
+
if (tNodeType & 8 /* TNodeType.ElementContainer */) {
|
|
12282
|
+
collectNativeNodes(tView, lView, tNode.child, result);
|
|
12283
|
+
}
|
|
12284
|
+
else if (tNodeType & 32 /* TNodeType.Icu */) {
|
|
12285
|
+
const nextRNode = icuContainerIterate(tNode, lView);
|
|
12286
|
+
let rNode;
|
|
12287
|
+
while (rNode = nextRNode()) {
|
|
12288
|
+
result.push(rNode);
|
|
12289
|
+
}
|
|
12290
|
+
}
|
|
12291
|
+
else if (tNodeType & 16 /* TNodeType.Projection */) {
|
|
12292
|
+
const nodesInSlot = getProjectionNodes(lView, tNode);
|
|
12293
|
+
if (Array.isArray(nodesInSlot)) {
|
|
12294
|
+
result.push(...nodesInSlot);
|
|
12295
|
+
}
|
|
12296
|
+
else {
|
|
12297
|
+
const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
|
|
12298
|
+
ngDevMode && assertParentView(parentView);
|
|
12299
|
+
collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
|
|
12300
|
+
}
|
|
12301
|
+
}
|
|
12302
|
+
tNode = isProjection ? tNode.projectionNext : tNode.next;
|
|
12303
|
+
}
|
|
12304
|
+
return result;
|
|
12305
|
+
}
|
|
12306
|
+
|
|
12307
|
+
function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12308
|
+
const rendererFactory = lView[ENVIRONMENT].rendererFactory;
|
|
12309
|
+
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
12310
|
+
// since they were assigned. We do not want to invoke renderer factory functions in that mode
|
|
12311
|
+
// to avoid any possible side-effects.
|
|
12312
|
+
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
|
12313
|
+
if (!checkNoChangesMode && rendererFactory.begin)
|
|
12314
|
+
rendererFactory.begin();
|
|
12315
|
+
try {
|
|
12316
|
+
refreshView(tView, lView, tView.template, context);
|
|
12317
|
+
}
|
|
12318
|
+
catch (error) {
|
|
12319
|
+
if (notifyErrorHandler) {
|
|
12320
|
+
handleError(lView, error);
|
|
12321
|
+
}
|
|
12322
|
+
throw error;
|
|
12323
|
+
}
|
|
12324
|
+
finally {
|
|
12325
|
+
if (!checkNoChangesMode && rendererFactory.end)
|
|
12326
|
+
rendererFactory.end();
|
|
12327
|
+
// One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
|
|
12328
|
+
// other post-order hooks.
|
|
12329
|
+
!checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
|
|
12330
|
+
}
|
|
12331
|
+
}
|
|
12332
|
+
function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12333
|
+
setIsInCheckNoChangesMode(true);
|
|
12334
|
+
try {
|
|
12335
|
+
detectChangesInternal(tView, lView, context, notifyErrorHandler);
|
|
12336
|
+
}
|
|
12337
|
+
finally {
|
|
12338
|
+
setIsInCheckNoChangesMode(false);
|
|
12339
|
+
}
|
|
12340
|
+
}
|
|
12341
|
+
/**
|
|
12342
|
+
* Synchronously perform change detection on a component (and possibly its sub-components).
|
|
12343
|
+
*
|
|
12344
|
+
* This function triggers change detection in a synchronous way on a component.
|
|
12345
|
+
*
|
|
12346
|
+
* @param component The component which the change detection should be performed on.
|
|
12347
|
+
*/
|
|
12348
|
+
function detectChanges(component) {
|
|
12349
|
+
const view = getComponentViewByInstance(component);
|
|
12350
|
+
detectChangesInternal(view[TVIEW], view, component);
|
|
12351
|
+
}
|
|
12352
|
+
/**
|
|
12353
|
+
* Processes a view in update mode. This includes a number of steps in a specific order:
|
|
12354
|
+
* - executing a template function in update mode;
|
|
12355
|
+
* - executing hooks;
|
|
12356
|
+
* - refreshing queries;
|
|
12357
|
+
* - setting host bindings;
|
|
12358
|
+
* - refreshing child (embedded and component) views.
|
|
12359
|
+
*/
|
|
12360
|
+
function refreshView(tView, lView, templateFn, context) {
|
|
12361
|
+
ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
|
|
12362
|
+
const flags = lView[FLAGS];
|
|
12363
|
+
if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
|
|
12364
|
+
return;
|
|
12365
|
+
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
12366
|
+
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
|
12367
|
+
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
12368
|
+
!isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
|
|
12369
|
+
enterView(lView);
|
|
12370
|
+
try {
|
|
12371
|
+
resetPreOrderHookFlags(lView);
|
|
12372
|
+
setBindingIndex(tView.bindingStartIndex);
|
|
12373
|
+
if (templateFn !== null) {
|
|
12374
|
+
executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
|
|
12375
|
+
}
|
|
12376
|
+
const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
|
|
12377
|
+
// execute pre-order hooks (OnInit, OnChanges, DoCheck)
|
|
12378
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12379
|
+
if (!isInCheckNoChangesPass) {
|
|
12380
|
+
if (hooksInitPhaseCompleted) {
|
|
12381
|
+
const preOrderCheckHooks = tView.preOrderCheckHooks;
|
|
12382
|
+
if (preOrderCheckHooks !== null) {
|
|
12383
|
+
executeCheckHooks(lView, preOrderCheckHooks, null);
|
|
12384
|
+
}
|
|
12385
|
+
}
|
|
12386
|
+
else {
|
|
12387
|
+
const preOrderHooks = tView.preOrderHooks;
|
|
12388
|
+
if (preOrderHooks !== null) {
|
|
12389
|
+
executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
|
|
12390
|
+
}
|
|
12391
|
+
incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
|
|
12392
|
+
}
|
|
12393
|
+
}
|
|
12394
|
+
// First mark transplanted views that are declared in this lView as needing a refresh at their
|
|
12395
|
+
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
12396
|
+
// `LView` but its declaration appears after the insertion component.
|
|
12397
|
+
markTransplantedViewsForRefresh(lView);
|
|
12398
|
+
refreshEmbeddedViews(lView);
|
|
12399
|
+
// Content query results must be refreshed before content hooks are called.
|
|
12400
|
+
if (tView.contentQueries !== null) {
|
|
12401
|
+
refreshContentQueries(tView, lView);
|
|
12402
|
+
}
|
|
12403
|
+
// execute content hooks (AfterContentInit, AfterContentChecked)
|
|
12404
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12405
|
+
if (!isInCheckNoChangesPass) {
|
|
12406
|
+
if (hooksInitPhaseCompleted) {
|
|
12407
|
+
const contentCheckHooks = tView.contentCheckHooks;
|
|
12408
|
+
if (contentCheckHooks !== null) {
|
|
12409
|
+
executeCheckHooks(lView, contentCheckHooks);
|
|
12410
|
+
}
|
|
12411
|
+
}
|
|
12412
|
+
else {
|
|
12413
|
+
const contentHooks = tView.contentHooks;
|
|
12414
|
+
if (contentHooks !== null) {
|
|
12415
|
+
executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
12416
|
+
}
|
|
12417
|
+
incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
12418
|
+
}
|
|
12419
|
+
}
|
|
12420
|
+
processHostBindingOpCodes(tView, lView);
|
|
12421
|
+
// Refresh child component views.
|
|
12422
|
+
const components = tView.components;
|
|
12423
|
+
if (components !== null) {
|
|
12424
|
+
refreshChildComponents(lView, components);
|
|
12425
|
+
}
|
|
12426
|
+
// View queries must execute after refreshing child components because a template in this view
|
|
12427
|
+
// could be inserted in a child component. If the view query executes before child component
|
|
12428
|
+
// refresh, the template might not yet be inserted.
|
|
12429
|
+
const viewQuery = tView.viewQuery;
|
|
12430
|
+
if (viewQuery !== null) {
|
|
12431
|
+
executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
|
|
12432
|
+
}
|
|
12433
|
+
// execute view hooks (AfterViewInit, AfterViewChecked)
|
|
12434
|
+
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
12435
|
+
if (!isInCheckNoChangesPass) {
|
|
12436
|
+
if (hooksInitPhaseCompleted) {
|
|
12437
|
+
const viewCheckHooks = tView.viewCheckHooks;
|
|
12438
|
+
if (viewCheckHooks !== null) {
|
|
12439
|
+
executeCheckHooks(lView, viewCheckHooks);
|
|
12440
|
+
}
|
|
12441
|
+
}
|
|
12442
|
+
else {
|
|
12443
|
+
const viewHooks = tView.viewHooks;
|
|
12444
|
+
if (viewHooks !== null) {
|
|
12445
|
+
executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
12446
|
+
}
|
|
12447
|
+
incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
12448
|
+
}
|
|
12449
|
+
}
|
|
12450
|
+
if (tView.firstUpdatePass === true) {
|
|
12451
|
+
// We need to make sure that we only flip the flag on successful `refreshView` only
|
|
12452
|
+
// Don't do this in `finally` block.
|
|
12453
|
+
// If we did this in `finally` block then an exception could block the execution of styling
|
|
12454
|
+
// instructions which in turn would be unable to insert themselves into the styling linked
|
|
12455
|
+
// list. The result of this would be that if the exception would not be throw on subsequent CD
|
|
12456
|
+
// the styling would be unable to process it data and reflect to the DOM.
|
|
12457
|
+
tView.firstUpdatePass = false;
|
|
12458
|
+
}
|
|
12459
|
+
// Do not reset the dirty state when running in check no changes mode. We don't want components
|
|
12460
|
+
// to behave differently depending on whether check no changes is enabled or not. For example:
|
|
12461
|
+
// Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
|
|
12462
|
+
// refresh a `NgClass` binding should work. If we would reset the dirty state in the check
|
|
12463
|
+
// no changes cycle, the component would be not be dirty for the next update pass. This would
|
|
12464
|
+
// be different in production mode where the component dirty state is not reset.
|
|
12465
|
+
if (!isInCheckNoChangesPass) {
|
|
12466
|
+
lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
|
|
12467
|
+
}
|
|
12468
|
+
clearViewRefreshFlag(lView);
|
|
12355
12469
|
}
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
return () => removeLViewOnDestroy(this._lView, callback);
|
|
12470
|
+
finally {
|
|
12471
|
+
leaveView();
|
|
12359
12472
|
}
|
|
12360
12473
|
}
|
|
12361
|
-
function injectDestroyRef() {
|
|
12362
|
-
return new NodeInjectorDestroyRef(getLView());
|
|
12363
|
-
}
|
|
12364
|
-
|
|
12365
12474
|
/**
|
|
12366
|
-
*
|
|
12475
|
+
* Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
|
|
12476
|
+
* them by executing an associated template function.
|
|
12367
12477
|
*/
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
if (!this.all.has(watch)) {
|
|
12377
|
-
return;
|
|
12478
|
+
function refreshEmbeddedViews(lView) {
|
|
12479
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12480
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12481
|
+
const embeddedLView = lContainer[i];
|
|
12482
|
+
const embeddedTView = embeddedLView[TVIEW];
|
|
12483
|
+
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12484
|
+
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12485
|
+
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12378
12486
|
}
|
|
12379
|
-
this.queue.set(watch, zone);
|
|
12380
|
-
}, allowSignalWrites);
|
|
12381
|
-
this.all.add(watch);
|
|
12382
|
-
// Effects start dirty.
|
|
12383
|
-
watch.notify();
|
|
12384
|
-
let unregisterOnDestroy;
|
|
12385
|
-
const destroy = () => {
|
|
12386
|
-
watch.cleanup();
|
|
12387
|
-
unregisterOnDestroy?.();
|
|
12388
|
-
this.all.delete(watch);
|
|
12389
|
-
this.queue.delete(watch);
|
|
12390
|
-
};
|
|
12391
|
-
unregisterOnDestroy = destroyRef?.onDestroy(destroy);
|
|
12392
|
-
return {
|
|
12393
|
-
destroy,
|
|
12394
|
-
};
|
|
12395
|
-
}
|
|
12396
|
-
flush() {
|
|
12397
|
-
if (this.queue.size === 0) {
|
|
12398
|
-
return;
|
|
12399
|
-
}
|
|
12400
|
-
for (const [watch, zone] of this.queue) {
|
|
12401
|
-
this.queue.delete(watch);
|
|
12402
|
-
zone.run(() => watch.run());
|
|
12403
12487
|
}
|
|
12404
12488
|
}
|
|
12405
|
-
get isQueueEmpty() {
|
|
12406
|
-
return this.queue.size === 0;
|
|
12407
|
-
}
|
|
12408
|
-
/** @nocollapse */
|
|
12409
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
12410
|
-
token: EffectManager,
|
|
12411
|
-
providedIn: 'root',
|
|
12412
|
-
factory: () => new EffectManager(),
|
|
12413
|
-
}); }
|
|
12414
12489
|
}
|
|
12415
12490
|
/**
|
|
12416
|
-
*
|
|
12491
|
+
* Mark transplanted views as needing to be refreshed at their insertion points.
|
|
12417
12492
|
*
|
|
12418
|
-
* @
|
|
12493
|
+
* @param lView The `LView` that may have transplanted views.
|
|
12419
12494
|
*/
|
|
12420
|
-
function
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12495
|
+
function markTransplantedViewsForRefresh(lView) {
|
|
12496
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12497
|
+
if (!lContainer[HAS_TRANSPLANTED_VIEWS])
|
|
12498
|
+
continue;
|
|
12499
|
+
const movedViews = lContainer[MOVED_VIEWS];
|
|
12500
|
+
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
|
|
12501
|
+
for (let i = 0; i < movedViews.length; i++) {
|
|
12502
|
+
const movedLView = movedViews[i];
|
|
12503
|
+
const insertionLContainer = movedLView[PARENT];
|
|
12504
|
+
ngDevMode && assertLContainer(insertionLContainer);
|
|
12505
|
+
markViewForRefresh(movedLView);
|
|
12506
|
+
}
|
|
12507
|
+
}
|
|
12426
12508
|
}
|
|
12427
|
-
|
|
12428
12509
|
/**
|
|
12429
|
-
*
|
|
12430
|
-
*
|
|
12431
|
-
* This function should be called during `firstCreatePass` only.
|
|
12510
|
+
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12432
12511
|
*
|
|
12433
|
-
* @param
|
|
12434
|
-
* @param attrs `TAttributes` containing the styling information.
|
|
12435
|
-
* @param writeToHost Where should the resulting static styles be written?
|
|
12436
|
-
* - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
|
|
12437
|
-
* - `true` Write to `TNode.styles` / `TNode.classes`
|
|
12512
|
+
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12438
12513
|
*/
|
|
12439
|
-
function
|
|
12440
|
-
ngDevMode &&
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
else if (mode == 1 /* AttributeMarker.Classes */) {
|
|
12452
|
-
classes = concatStringsWithSpace(classes, value);
|
|
12453
|
-
}
|
|
12454
|
-
else if (mode == 2 /* AttributeMarker.Styles */) {
|
|
12455
|
-
const style = value;
|
|
12456
|
-
const styleValue = attrs[++i];
|
|
12457
|
-
styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
|
|
12458
|
-
}
|
|
12514
|
+
function refreshComponent(hostLView, componentHostIdx) {
|
|
12515
|
+
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12516
|
+
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12517
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12518
|
+
if (viewAttachedToChangeDetector(componentView)) {
|
|
12519
|
+
const tView = componentView[TVIEW];
|
|
12520
|
+
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12521
|
+
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12522
|
+
}
|
|
12523
|
+
else if (componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12524
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12525
|
+
refreshContainsDirtyView(componentView);
|
|
12459
12526
|
}
|
|
12460
12527
|
}
|
|
12461
|
-
writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
|
|
12462
|
-
writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
|
|
12463
12528
|
}
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
if (
|
|
12481
|
-
|
|
12529
|
+
/**
|
|
12530
|
+
* Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
|
|
12531
|
+
* children or descendants of the given lView.
|
|
12532
|
+
*
|
|
12533
|
+
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12534
|
+
*/
|
|
12535
|
+
function refreshContainsDirtyView(lView) {
|
|
12536
|
+
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12537
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12538
|
+
const embeddedLView = lContainer[i];
|
|
12539
|
+
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12540
|
+
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
|
|
12541
|
+
const embeddedTView = embeddedLView[TVIEW];
|
|
12542
|
+
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12543
|
+
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12544
|
+
}
|
|
12545
|
+
else if (embeddedLView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12546
|
+
refreshContainsDirtyView(embeddedLView);
|
|
12482
12547
|
}
|
|
12483
12548
|
}
|
|
12484
12549
|
}
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
else if (tNodeType & 16 /* TNodeType.Projection */) {
|
|
12497
|
-
const nodesInSlot = getProjectionNodes(lView, tNode);
|
|
12498
|
-
if (Array.isArray(nodesInSlot)) {
|
|
12499
|
-
result.push(...nodesInSlot);
|
|
12500
|
-
}
|
|
12501
|
-
else {
|
|
12502
|
-
const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
|
|
12503
|
-
ngDevMode && assertParentView(parentView);
|
|
12504
|
-
collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
|
|
12550
|
+
}
|
|
12551
|
+
const tView = lView[TVIEW];
|
|
12552
|
+
// Refresh child component views.
|
|
12553
|
+
const components = tView.components;
|
|
12554
|
+
if (components !== null) {
|
|
12555
|
+
for (let i = 0; i < components.length; i++) {
|
|
12556
|
+
const componentView = getComponentLViewByIndex(components[i], lView);
|
|
12557
|
+
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12558
|
+
if (viewAttachedToChangeDetector(componentView) &&
|
|
12559
|
+
componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12560
|
+
refreshContainsDirtyView(componentView);
|
|
12505
12561
|
}
|
|
12506
12562
|
}
|
|
12507
|
-
tNode = isProjection ? tNode.projectionNext : tNode.next;
|
|
12508
12563
|
}
|
|
12509
|
-
|
|
12564
|
+
}
|
|
12565
|
+
/** Refreshes child components in the current view (update mode). */
|
|
12566
|
+
function refreshChildComponents(hostLView, components) {
|
|
12567
|
+
for (let i = 0; i < components.length; i++) {
|
|
12568
|
+
refreshComponent(hostLView, components[i]);
|
|
12569
|
+
}
|
|
12510
12570
|
}
|
|
12511
12571
|
|
|
12512
12572
|
class ViewRef$1 {
|
|
@@ -14191,18 +14251,6 @@ function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
|
|
|
14191
14251
|
return ɵɵattributeInterpolateV;
|
|
14192
14252
|
}
|
|
14193
14253
|
|
|
14194
|
-
/**
|
|
14195
|
-
* Synchronously perform change detection on a component (and possibly its sub-components).
|
|
14196
|
-
*
|
|
14197
|
-
* This function triggers change detection in a synchronous way on a component.
|
|
14198
|
-
*
|
|
14199
|
-
* @param component The component which the change detection should be performed on.
|
|
14200
|
-
*/
|
|
14201
|
-
function detectChanges(component) {
|
|
14202
|
-
const view = getComponentViewByInstance(component);
|
|
14203
|
-
detectChangesInternal(view[TVIEW], view, component);
|
|
14204
|
-
}
|
|
14205
|
-
|
|
14206
14254
|
const AT_THIS_LOCATION = '<-- AT THIS LOCATION';
|
|
14207
14255
|
/**
|
|
14208
14256
|
* Retrieves a user friendly string for a given TNodeType for use in
|
|
@@ -14276,9 +14324,16 @@ function validateSiblingNodeExists(node) {
|
|
|
14276
14324
|
/**
|
|
14277
14325
|
* Validates that a node exists or throws
|
|
14278
14326
|
*/
|
|
14279
|
-
function validateNodeExists(node) {
|
|
14327
|
+
function validateNodeExists(node, lView = null, tNode = null) {
|
|
14280
14328
|
if (!node) {
|
|
14281
|
-
|
|
14329
|
+
const header = 'During hydration, Angular expected an element to be present at this location.\n\n';
|
|
14330
|
+
let expected = '';
|
|
14331
|
+
let footer = '';
|
|
14332
|
+
if (lView !== null && tNode !== null) {
|
|
14333
|
+
expected = `${describeExpectedDom(lView, tNode, false)}\n\n`;
|
|
14334
|
+
footer = getHydrationErrorFooter();
|
|
14335
|
+
}
|
|
14336
|
+
throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + expected + footer);
|
|
14282
14337
|
}
|
|
14283
14338
|
}
|
|
14284
14339
|
/**
|
|
@@ -14335,7 +14390,7 @@ function invalidSkipHydrationHost(rNode) {
|
|
|
14335
14390
|
'that doesn\'t act as a component host. Hydration can be ' +
|
|
14336
14391
|
'skipped only on per-component basis.\n\n';
|
|
14337
14392
|
const actual = `${describeDomFromNode(rNode)}\n\n`;
|
|
14338
|
-
const footer = 'Please move the `ngSkipHydration` attribute to the component host element
|
|
14393
|
+
const footer = 'Please move the `ngSkipHydration` attribute to the component host element.\n\n';
|
|
14339
14394
|
const message = header + actual + footer;
|
|
14340
14395
|
return new RuntimeError(-504 /* RuntimeErrorCode.INVALID_SKIP_HYDRATION_HOST */, message);
|
|
14341
14396
|
}
|
|
@@ -14520,8 +14575,9 @@ function getHydrationErrorFooter(componentClassName) {
|
|
|
14520
14575
|
const componentInfo = componentClassName ? `the "${componentClassName}"` : 'corresponding';
|
|
14521
14576
|
return `To fix this problem:\n` +
|
|
14522
14577
|
` * check ${componentInfo} component for hydration-related issues\n` +
|
|
14578
|
+
` * check to see if your template has valid HTML structure\n` +
|
|
14523
14579
|
` * or skip hydration by adding the \`ngSkipHydration\` attribute ` +
|
|
14524
|
-
`to its host node in a template`;
|
|
14580
|
+
`to its host node in a template\n\n`;
|
|
14525
14581
|
}
|
|
14526
14582
|
/**
|
|
14527
14583
|
* An attribute related note for hydration errors
|
|
@@ -14748,10 +14804,10 @@ function locateRNodeByPath(path, lView) {
|
|
|
14748
14804
|
const [referenceNode, ...navigationInstructions] = decompressNodeLocation(path);
|
|
14749
14805
|
let ref;
|
|
14750
14806
|
if (referenceNode === REFERENCE_NODE_HOST) {
|
|
14751
|
-
ref = lView[
|
|
14807
|
+
ref = lView[DECLARATION_COMPONENT_VIEW][HOST];
|
|
14752
14808
|
}
|
|
14753
14809
|
else if (referenceNode === REFERENCE_NODE_BODY) {
|
|
14754
|
-
ref = ɵɵresolveBody(lView[
|
|
14810
|
+
ref = ɵɵresolveBody(lView[DECLARATION_COMPONENT_VIEW][HOST]);
|
|
14755
14811
|
}
|
|
14756
14812
|
else {
|
|
14757
14813
|
const parentElementId = Number(referenceNode);
|
|
@@ -14795,6 +14851,7 @@ function navigateBetween(start, finish) {
|
|
|
14795
14851
|
}
|
|
14796
14852
|
/**
|
|
14797
14853
|
* Calculates a path between 2 sibling nodes (generates a number of `NextSibling` navigations).
|
|
14854
|
+
* Returns `null` if no such path exists between the given nodes.
|
|
14798
14855
|
*/
|
|
14799
14856
|
function navigateBetweenSiblings(start, finish) {
|
|
14800
14857
|
const nav = [];
|
|
@@ -14802,7 +14859,10 @@ function navigateBetweenSiblings(start, finish) {
|
|
|
14802
14859
|
for (node = start; node != null && node !== finish; node = node.nextSibling) {
|
|
14803
14860
|
nav.push(NodeNavigationStep.NextSibling);
|
|
14804
14861
|
}
|
|
14805
|
-
|
|
14862
|
+
// If the `node` becomes `null` or `undefined` at the end, that means that we
|
|
14863
|
+
// didn't find the `end` node, thus return `null` (which would trigger serialization
|
|
14864
|
+
// error to be produced).
|
|
14865
|
+
return node == null ? null : nav;
|
|
14806
14866
|
}
|
|
14807
14867
|
/**
|
|
14808
14868
|
* Calculates a path between 2 nodes in terms of `nextSibling` and `firstChild`
|
|
@@ -14825,10 +14885,11 @@ function calcPathForNode(tNode, lView) {
|
|
|
14825
14885
|
let parentIndex;
|
|
14826
14886
|
let parentRNode;
|
|
14827
14887
|
let referenceNodeName;
|
|
14828
|
-
if (parentTNode === null) {
|
|
14829
|
-
//
|
|
14888
|
+
if (parentTNode === null || !(parentTNode.type & 3 /* TNodeType.AnyRNode */)) {
|
|
14889
|
+
// If there is no parent TNode or a parent TNode does not represent an RNode
|
|
14890
|
+
// (i.e. not a DOM node), use component host element as a reference node.
|
|
14830
14891
|
parentIndex = referenceNodeName = REFERENCE_NODE_HOST;
|
|
14831
|
-
parentRNode = lView[HOST];
|
|
14892
|
+
parentRNode = lView[DECLARATION_COMPONENT_VIEW][HOST];
|
|
14832
14893
|
}
|
|
14833
14894
|
else {
|
|
14834
14895
|
// Use parent TNode as a reference node.
|
|
@@ -14876,17 +14937,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
|
|
|
14876
14937
|
ngDevMode && assertFirstCreatePass(tView);
|
|
14877
14938
|
ngDevMode && ngDevMode.firstCreatePass++;
|
|
14878
14939
|
const tViewConsts = tView.consts;
|
|
14879
|
-
let ssrId = null;
|
|
14880
|
-
const hydrationInfo = lView[HYDRATION];
|
|
14881
|
-
if (hydrationInfo) {
|
|
14882
|
-
const noOffsetIndex = index - HEADER_OFFSET;
|
|
14883
|
-
ssrId = (hydrationInfo && hydrationInfo.data[TEMPLATES]?.[noOffsetIndex]) ?? null;
|
|
14884
|
-
}
|
|
14885
14940
|
// TODO(pk): refactor getOrCreateTNode to have the "create" only version
|
|
14886
14941
|
const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
|
|
14887
14942
|
resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
|
|
14888
14943
|
registerPostOrderHooks(tView, tNode);
|
|
14889
|
-
const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, ssrId);
|
|
14944
|
+
const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */);
|
|
14890
14945
|
if (tView.queries !== null) {
|
|
14891
14946
|
tView.queries.template(tView, tNode);
|
|
14892
14947
|
embeddedTView.queries = tView.queries.embeddedTView(tNode);
|
|
@@ -14953,9 +15008,27 @@ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
|
|
|
14953
15008
|
if (isNodeCreationMode) {
|
|
14954
15009
|
return createContainerAnchorImpl(tView, lView, tNode, index);
|
|
14955
15010
|
}
|
|
15011
|
+
const ssrId = hydrationInfo.data[TEMPLATES]?.[index] ?? null;
|
|
15012
|
+
// Apply `ssrId` value to the underlying TView if it was not previously set.
|
|
15013
|
+
//
|
|
15014
|
+
// There might be situations when the same component is present in a template
|
|
15015
|
+
// multiple times and some instances are opted-out of using hydration via
|
|
15016
|
+
// `ngSkipHydration` attribute. In this scenario, at the time a TView is created,
|
|
15017
|
+
// the `ssrId` might be `null` (if the first component is opted-out of hydration).
|
|
15018
|
+
// The code below makes sure that the `ssrId` is applied to the TView if it's still
|
|
15019
|
+
// `null` and verifies we never try to override it with a different value.
|
|
15020
|
+
if (ssrId !== null && tNode.tView !== null) {
|
|
15021
|
+
if (tNode.tView.ssrId === null) {
|
|
15022
|
+
tNode.tView.ssrId = ssrId;
|
|
15023
|
+
}
|
|
15024
|
+
else {
|
|
15025
|
+
ngDevMode &&
|
|
15026
|
+
assertEqual(tNode.tView.ssrId, ssrId, 'Unexpected value of the `ssrId` for this TView');
|
|
15027
|
+
}
|
|
15028
|
+
}
|
|
14956
15029
|
// Hydration mode, looking up existing elements in DOM.
|
|
14957
15030
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
14958
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15031
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
14959
15032
|
setSegmentHead(hydrationInfo, index, currentRNode);
|
|
14960
15033
|
const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
|
|
14961
15034
|
const comment = siblingAfter(viewContainerSize, currentRNode);
|
|
@@ -15189,7 +15262,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
|
|
|
15189
15262
|
// `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
|
|
15190
15263
|
// so while processing a `<div>` instruction, point to the next sibling as a
|
|
15191
15264
|
// start of a segment.
|
|
15192
|
-
ngDevMode && validateNodeExists(native.nextSibling);
|
|
15265
|
+
ngDevMode && validateNodeExists(native.nextSibling, lView, tNode);
|
|
15193
15266
|
setSegmentHead(hydrationInfo, index, native.nextSibling);
|
|
15194
15267
|
}
|
|
15195
15268
|
// Checks if the skip hydration attribute is present during hydration so we know to
|
|
@@ -15334,7 +15407,7 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
|
|
|
15334
15407
|
}
|
|
15335
15408
|
// Hydration mode, looking up existing elements in DOM.
|
|
15336
15409
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
15337
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15410
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
15338
15411
|
const ngContainerSize = getNgContainerSize(hydrationInfo, index);
|
|
15339
15412
|
ngDevMode &&
|
|
15340
15413
|
assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
|
|
@@ -16997,7 +17070,7 @@ function styleStringParser(keyValueArray, text) {
|
|
|
16997
17070
|
* @codeGenApi
|
|
16998
17071
|
*/
|
|
16999
17072
|
function ɵɵclassMap(classes) {
|
|
17000
|
-
checkStylingMap(
|
|
17073
|
+
checkStylingMap(classKeyValueArraySet, classStringParser, classes, true);
|
|
17001
17074
|
}
|
|
17002
17075
|
/**
|
|
17003
17076
|
* Parse text as class and add values to KeyValueArray.
|
|
@@ -17439,6 +17512,26 @@ function toStylingKeyValueArray(keyValueArraySet, stringParser, value) {
|
|
|
17439
17512
|
function styleKeyValueArraySet(keyValueArray, key, value) {
|
|
17440
17513
|
keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
|
|
17441
17514
|
}
|
|
17515
|
+
/**
|
|
17516
|
+
* Class-binding-specific function for setting the `value` for a `key`.
|
|
17517
|
+
*
|
|
17518
|
+
* See: `keyValueArraySet` for details
|
|
17519
|
+
*
|
|
17520
|
+
* @param keyValueArray KeyValueArray to add to.
|
|
17521
|
+
* @param key Style key to add.
|
|
17522
|
+
* @param value The value to set.
|
|
17523
|
+
*/
|
|
17524
|
+
function classKeyValueArraySet(keyValueArray, key, value) {
|
|
17525
|
+
// We use `classList.add` to eventually add the CSS classes to the DOM node. Any value passed into
|
|
17526
|
+
// `add` is stringified and added to the `class` attribute, e.g. even null, undefined or numbers
|
|
17527
|
+
// will be added. Stringify the key here so that our internal data structure matches the value in
|
|
17528
|
+
// the DOM. The only exceptions are empty strings and strings that contain spaces for which
|
|
17529
|
+
// the browser throws an error. We ignore such values, because the error is somewhat cryptic.
|
|
17530
|
+
const stringKey = String(key);
|
|
17531
|
+
if (stringKey !== '' && !stringKey.includes(' ')) {
|
|
17532
|
+
keyValueArraySet(keyValueArray, stringKey, value);
|
|
17533
|
+
}
|
|
17534
|
+
}
|
|
17442
17535
|
/**
|
|
17443
17536
|
* Update map based styling.
|
|
17444
17537
|
*
|
|
@@ -20168,11 +20261,10 @@ const MARKER = `�`;
|
|
|
20168
20261
|
const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
|
|
20169
20262
|
const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi;
|
|
20170
20263
|
/**
|
|
20171
|
-
* Angular
|
|
20172
|
-
*
|
|
20173
|
-
*
|
|
20174
|
-
*
|
|
20175
|
-
* might contain this special character.
|
|
20264
|
+
* Angular uses the special entity &ngsp; as a placeholder for non-removable space.
|
|
20265
|
+
* It's replaced by the 0xE500 PUA (Private Use Areas) unicode character and later on replaced by a
|
|
20266
|
+
* space.
|
|
20267
|
+
* We are re-implementing the same idea since translations might contain this special character.
|
|
20176
20268
|
*/
|
|
20177
20269
|
const NGSP_UNICODE_REGEXP = /\uE500/g;
|
|
20178
20270
|
function replaceNgsp(value) {
|
|
@@ -25196,8 +25288,13 @@ class ApplicationInitStatus {
|
|
|
25196
25288
|
this.resolve = res;
|
|
25197
25289
|
this.reject = rej;
|
|
25198
25290
|
});
|
|
25199
|
-
// TODO: Throw RuntimeErrorCode.INVALID_MULTI_PROVIDER if appInits is not an array
|
|
25200
25291
|
this.appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
|
|
25292
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
|
|
25293
|
+
throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
|
|
25294
|
+
`(expected an array, but got ${typeof this.appInits}). ` +
|
|
25295
|
+
'Please check that the `APP_INITIALIZER` token is configured as a ' +
|
|
25296
|
+
'`multi: true` provider.');
|
|
25297
|
+
}
|
|
25201
25298
|
}
|
|
25202
25299
|
/** @internal */
|
|
25203
25300
|
runInitializers() {
|
|
@@ -25240,7 +25337,7 @@ class ApplicationInitStatus {
|
|
|
25240
25337
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
|
|
25241
25338
|
type: Injectable,
|
|
25242
25339
|
args: [{ providedIn: 'root' }]
|
|
25243
|
-
}],
|
|
25340
|
+
}], function () { return []; }, null); })();
|
|
25244
25341
|
|
|
25245
25342
|
class Console {
|
|
25246
25343
|
log(message) {
|
|
@@ -26533,6 +26630,7 @@ function createOrReusePlatformInjector(providers = []) {
|
|
|
26533
26630
|
const injector = createPlatformInjector(providers);
|
|
26534
26631
|
_platformInjector = injector;
|
|
26535
26632
|
publishDefaultGlobalUtils();
|
|
26633
|
+
publishSignalConfiguration();
|
|
26536
26634
|
runPlatformInitializers(injector);
|
|
26537
26635
|
return injector;
|
|
26538
26636
|
}
|
|
@@ -29509,7 +29607,10 @@ function serializeLView(lView, context) {
|
|
|
29509
29607
|
// live DOM has exactly the same state as it was before serialization.
|
|
29510
29608
|
if (tNode.type & 1 /* TNodeType.Text */) {
|
|
29511
29609
|
const rNode = unwrapRNode(lView[i]);
|
|
29512
|
-
|
|
29610
|
+
// Collect this node as required special annotation only when its
|
|
29611
|
+
// contents is empty. Otherwise, such text node would be present on
|
|
29612
|
+
// the client after server-side rendering and no special handling needed.
|
|
29613
|
+
if (rNode.textContent === '') {
|
|
29513
29614
|
context.corruptedTextNodes.set(rNode, "ngetn" /* TextNodeMarker.EmptyNode */);
|
|
29514
29615
|
}
|
|
29515
29616
|
else if (rNode.nextSibling?.nodeType === Node.TEXT_NODE) {
|
|
@@ -29750,7 +29851,7 @@ function withDomHydration() {
|
|
|
29750
29851
|
// hydration annotations. Otherwise, keep hydration disabled.
|
|
29751
29852
|
const transferState = inject(TransferState, { optional: true });
|
|
29752
29853
|
isEnabled = !!transferState?.get(NGH_DATA_KEY, null);
|
|
29753
|
-
if (!isEnabled) {
|
|
29854
|
+
if (!isEnabled && (typeof ngDevMode !== 'undefined' && ngDevMode)) {
|
|
29754
29855
|
const console = inject(Console);
|
|
29755
29856
|
const message = formatRuntimeError(-505 /* RuntimeErrorCode.MISSING_HYDRATION_ANNOTATIONS */, 'Angular hydration was requested on the client, but there was no ' +
|
|
29756
29857
|
'serialized information present in the server response, ' +
|