@angular/core 16.0.0-rc.2 → 16.0.0-rc.4
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/index.mjs +1 -1
- package/esm2022/rxjs-interop/src/take_until_destroyed.mjs +3 -2
- package/esm2022/rxjs-interop/src/to_observable.mjs +20 -19
- package/esm2022/rxjs-interop/src/to_signal.mjs +6 -5
- 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/error_handling.mjs +13 -5
- package/esm2022/src/linker/template_ref.mjs +3 -2
- package/esm2022/src/render3/component_ref.mjs +3 -2
- package/esm2022/src/render3/definition.mjs +4 -5
- 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 +23 -405
- 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/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/fesm2022/core.mjs +647 -618
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +29 -26
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +639 -618
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +24 -10
- package/package.json +1 -1
- package/rxjs-interop/index.d.ts +111 -20
- 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 +371 -350
- package/schematics/ng-generate/standalone-migration/bundle.js.map +2 -2
- package/testing/index.d.ts +3 -3
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.4
|
|
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.4');
|
|
9967
9985
|
|
|
9968
9986
|
// This default value is when checking the hierarchy for a token.
|
|
9969
9987
|
//
|
|
@@ -10717,36 +10735,6 @@ function processHostBindingOpCodes(tView, lView) {
|
|
|
10717
10735
|
setSelectedIndex(-1);
|
|
10718
10736
|
}
|
|
10719
10737
|
}
|
|
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
|
-
}
|
|
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]);
|
|
10748
|
-
}
|
|
10749
|
-
}
|
|
10750
10738
|
function createLView(parentLView, tView, context, flags, host, tHostNode, environment, renderer, injector, embeddedViewInjector, hydrationInfo) {
|
|
10751
10739
|
const lView = tView.blueprint.slice();
|
|
10752
10740
|
lView[HOST] = host;
|
|
@@ -10863,195 +10851,6 @@ function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
|
|
|
10863
10851
|
}
|
|
10864
10852
|
return allocIdx;
|
|
10865
10853
|
}
|
|
10866
|
-
//////////////////////////
|
|
10867
|
-
//// Render
|
|
10868
|
-
//////////////////////////
|
|
10869
|
-
/**
|
|
10870
|
-
* Processes a view in the creation mode. This includes a number of steps in a specific order:
|
|
10871
|
-
* - creating view query functions (if any);
|
|
10872
|
-
* - executing a template function in the creation mode;
|
|
10873
|
-
* - updating static queries (if any);
|
|
10874
|
-
* - creating child components defined in a given view.
|
|
10875
|
-
*/
|
|
10876
|
-
function renderView(tView, lView, context) {
|
|
10877
|
-
ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
|
|
10878
|
-
enterView(lView);
|
|
10879
|
-
try {
|
|
10880
|
-
const viewQuery = tView.viewQuery;
|
|
10881
|
-
if (viewQuery !== null) {
|
|
10882
|
-
executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
|
|
10883
|
-
}
|
|
10884
|
-
// Execute a template associated with this view, if it exists. A template function might not be
|
|
10885
|
-
// defined for the root component views.
|
|
10886
|
-
const templateFn = tView.template;
|
|
10887
|
-
if (templateFn !== null) {
|
|
10888
|
-
executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
|
|
10889
|
-
}
|
|
10890
|
-
// This needs to be set before children are processed to support recursive components.
|
|
10891
|
-
// This must be set to false immediately after the first creation run because in an
|
|
10892
|
-
// ngFor loop, all the views will be created together before update mode runs and turns
|
|
10893
|
-
// off firstCreatePass. If we don't set it here, instances will perform directive
|
|
10894
|
-
// matching, etc again and again.
|
|
10895
|
-
if (tView.firstCreatePass) {
|
|
10896
|
-
tView.firstCreatePass = false;
|
|
10897
|
-
}
|
|
10898
|
-
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
|
10899
|
-
// content queries are resolved during change detection (i.e. update mode), after embedded
|
|
10900
|
-
// views are refreshed (see block above).
|
|
10901
|
-
if (tView.staticContentQueries) {
|
|
10902
|
-
refreshContentQueries(tView, lView);
|
|
10903
|
-
}
|
|
10904
|
-
// We must materialize query results before child components are processed
|
|
10905
|
-
// in case a child component has projected a container. The LContainer needs
|
|
10906
|
-
// to exist so the embedded views are properly attached by the container.
|
|
10907
|
-
if (tView.staticViewQueries) {
|
|
10908
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
|
|
10909
|
-
}
|
|
10910
|
-
// Render child component views.
|
|
10911
|
-
const components = tView.components;
|
|
10912
|
-
if (components !== null) {
|
|
10913
|
-
renderChildComponents(lView, components);
|
|
10914
|
-
}
|
|
10915
|
-
}
|
|
10916
|
-
catch (error) {
|
|
10917
|
-
// If we didn't manage to get past the first template pass due to
|
|
10918
|
-
// an error, mark the view as corrupted so we can try to recover.
|
|
10919
|
-
if (tView.firstCreatePass) {
|
|
10920
|
-
tView.incompleteFirstPass = true;
|
|
10921
|
-
tView.firstCreatePass = false;
|
|
10922
|
-
}
|
|
10923
|
-
throw error;
|
|
10924
|
-
}
|
|
10925
|
-
finally {
|
|
10926
|
-
lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
|
|
10927
|
-
leaveView();
|
|
10928
|
-
}
|
|
10929
|
-
}
|
|
10930
|
-
/**
|
|
10931
|
-
* Processes a view in update mode. This includes a number of steps in a specific order:
|
|
10932
|
-
* - executing a template function in update mode;
|
|
10933
|
-
* - executing hooks;
|
|
10934
|
-
* - refreshing queries;
|
|
10935
|
-
* - setting host bindings;
|
|
10936
|
-
* - refreshing child (embedded and component) views.
|
|
10937
|
-
*/
|
|
10938
|
-
function refreshView(tView, lView, templateFn, context) {
|
|
10939
|
-
ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
|
|
10940
|
-
const flags = lView[FLAGS];
|
|
10941
|
-
if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
|
|
10942
|
-
return;
|
|
10943
|
-
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
10944
|
-
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
|
10945
|
-
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
10946
|
-
!isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
|
|
10947
|
-
enterView(lView);
|
|
10948
|
-
try {
|
|
10949
|
-
resetPreOrderHookFlags(lView);
|
|
10950
|
-
setBindingIndex(tView.bindingStartIndex);
|
|
10951
|
-
if (templateFn !== null) {
|
|
10952
|
-
executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
|
|
10953
|
-
}
|
|
10954
|
-
const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
|
|
10955
|
-
// execute pre-order hooks (OnInit, OnChanges, DoCheck)
|
|
10956
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
10957
|
-
if (!isInCheckNoChangesPass) {
|
|
10958
|
-
if (hooksInitPhaseCompleted) {
|
|
10959
|
-
const preOrderCheckHooks = tView.preOrderCheckHooks;
|
|
10960
|
-
if (preOrderCheckHooks !== null) {
|
|
10961
|
-
executeCheckHooks(lView, preOrderCheckHooks, null);
|
|
10962
|
-
}
|
|
10963
|
-
}
|
|
10964
|
-
else {
|
|
10965
|
-
const preOrderHooks = tView.preOrderHooks;
|
|
10966
|
-
if (preOrderHooks !== null) {
|
|
10967
|
-
executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
|
|
10968
|
-
}
|
|
10969
|
-
incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
|
|
10970
|
-
}
|
|
10971
|
-
}
|
|
10972
|
-
// First mark transplanted views that are declared in this lView as needing a refresh at their
|
|
10973
|
-
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
10974
|
-
// `LView` but its declaration appears after the insertion component.
|
|
10975
|
-
markTransplantedViewsForRefresh(lView);
|
|
10976
|
-
refreshEmbeddedViews(lView);
|
|
10977
|
-
// Content query results must be refreshed before content hooks are called.
|
|
10978
|
-
if (tView.contentQueries !== null) {
|
|
10979
|
-
refreshContentQueries(tView, lView);
|
|
10980
|
-
}
|
|
10981
|
-
// execute content hooks (AfterContentInit, AfterContentChecked)
|
|
10982
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
10983
|
-
if (!isInCheckNoChangesPass) {
|
|
10984
|
-
if (hooksInitPhaseCompleted) {
|
|
10985
|
-
const contentCheckHooks = tView.contentCheckHooks;
|
|
10986
|
-
if (contentCheckHooks !== null) {
|
|
10987
|
-
executeCheckHooks(lView, contentCheckHooks);
|
|
10988
|
-
}
|
|
10989
|
-
}
|
|
10990
|
-
else {
|
|
10991
|
-
const contentHooks = tView.contentHooks;
|
|
10992
|
-
if (contentHooks !== null) {
|
|
10993
|
-
executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
10994
|
-
}
|
|
10995
|
-
incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
|
|
10996
|
-
}
|
|
10997
|
-
}
|
|
10998
|
-
processHostBindingOpCodes(tView, lView);
|
|
10999
|
-
// Refresh child component views.
|
|
11000
|
-
const components = tView.components;
|
|
11001
|
-
if (components !== null) {
|
|
11002
|
-
refreshChildComponents(lView, components);
|
|
11003
|
-
}
|
|
11004
|
-
// View queries must execute after refreshing child components because a template in this view
|
|
11005
|
-
// could be inserted in a child component. If the view query executes before child component
|
|
11006
|
-
// refresh, the template might not yet be inserted.
|
|
11007
|
-
const viewQuery = tView.viewQuery;
|
|
11008
|
-
if (viewQuery !== null) {
|
|
11009
|
-
executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
|
|
11010
|
-
}
|
|
11011
|
-
// execute view hooks (AfterViewInit, AfterViewChecked)
|
|
11012
|
-
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
|
11013
|
-
if (!isInCheckNoChangesPass) {
|
|
11014
|
-
if (hooksInitPhaseCompleted) {
|
|
11015
|
-
const viewCheckHooks = tView.viewCheckHooks;
|
|
11016
|
-
if (viewCheckHooks !== null) {
|
|
11017
|
-
executeCheckHooks(lView, viewCheckHooks);
|
|
11018
|
-
}
|
|
11019
|
-
}
|
|
11020
|
-
else {
|
|
11021
|
-
const viewHooks = tView.viewHooks;
|
|
11022
|
-
if (viewHooks !== null) {
|
|
11023
|
-
executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11024
|
-
}
|
|
11025
|
-
incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
|
|
11026
|
-
}
|
|
11027
|
-
}
|
|
11028
|
-
if (tView.firstUpdatePass === true) {
|
|
11029
|
-
// We need to make sure that we only flip the flag on successful `refreshView` only
|
|
11030
|
-
// Don't do this in `finally` block.
|
|
11031
|
-
// If we did this in `finally` block then an exception could block the execution of styling
|
|
11032
|
-
// instructions which in turn would be unable to insert themselves into the styling linked
|
|
11033
|
-
// list. The result of this would be that if the exception would not be throw on subsequent CD
|
|
11034
|
-
// the styling would be unable to process it data and reflect to the DOM.
|
|
11035
|
-
tView.firstUpdatePass = false;
|
|
11036
|
-
}
|
|
11037
|
-
// Do not reset the dirty state when running in check no changes mode. We don't want components
|
|
11038
|
-
// to behave differently depending on whether check no changes is enabled or not. For example:
|
|
11039
|
-
// Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
|
|
11040
|
-
// refresh a `NgClass` binding should work. If we would reset the dirty state in the check
|
|
11041
|
-
// no changes cycle, the component would be not be dirty for the next update pass. This would
|
|
11042
|
-
// be different in production mode where the component dirty state is not reset.
|
|
11043
|
-
if (!isInCheckNoChangesPass) {
|
|
11044
|
-
lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
|
|
11045
|
-
}
|
|
11046
|
-
if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
11047
|
-
lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
|
|
11048
|
-
updateTransplantedViewCount(lView[PARENT], -1);
|
|
11049
|
-
}
|
|
11050
|
-
}
|
|
11051
|
-
finally {
|
|
11052
|
-
leaveView();
|
|
11053
|
-
}
|
|
11054
|
-
}
|
|
11055
10854
|
function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
11056
10855
|
const consumer = getReactiveLViewConsumer(lView, REACTIVE_TEMPLATE_CONSUMER);
|
|
11057
10856
|
const prevSelectedIndex = getSelectedIndex();
|
|
@@ -12034,153 +11833,26 @@ function createLContainer(hostNative, currentView, native, tNode) {
|
|
|
12034
11833
|
assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
|
|
12035
11834
|
return lContainer;
|
|
12036
11835
|
}
|
|
12037
|
-
/**
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
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);
|
|
12049
11850
|
}
|
|
12050
11851
|
}
|
|
12051
11852
|
}
|
|
12052
11853
|
}
|
|
12053
11854
|
/**
|
|
12054
|
-
*
|
|
12055
|
-
*
|
|
12056
|
-
* @param lView The `LView` that may have transplanted views.
|
|
12057
|
-
*/
|
|
12058
|
-
function markTransplantedViewsForRefresh(lView) {
|
|
12059
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12060
|
-
if (!lContainer[HAS_TRANSPLANTED_VIEWS])
|
|
12061
|
-
continue;
|
|
12062
|
-
const movedViews = lContainer[MOVED_VIEWS];
|
|
12063
|
-
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
|
|
12064
|
-
for (let i = 0; i < movedViews.length; i++) {
|
|
12065
|
-
const movedLView = movedViews[i];
|
|
12066
|
-
const insertionLContainer = movedLView[PARENT];
|
|
12067
|
-
ngDevMode && assertLContainer(insertionLContainer);
|
|
12068
|
-
// We don't want to increment the counter if the moved LView was already marked for
|
|
12069
|
-
// refresh.
|
|
12070
|
-
if ((movedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) === 0) {
|
|
12071
|
-
updateTransplantedViewCount(insertionLContainer, 1);
|
|
12072
|
-
}
|
|
12073
|
-
// Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
|
|
12074
|
-
// those that aren't (declaration component === insertion component). In the latter case,
|
|
12075
|
-
// it's fine to add the flag, as we will clear it immediately in
|
|
12076
|
-
// `refreshEmbeddedViews` for the view currently being refreshed.
|
|
12077
|
-
movedLView[FLAGS] |= 1024 /* LViewFlags.RefreshTransplantedView */;
|
|
12078
|
-
}
|
|
12079
|
-
}
|
|
12080
|
-
}
|
|
12081
|
-
/////////////
|
|
12082
|
-
/**
|
|
12083
|
-
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12084
|
-
*
|
|
12085
|
-
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12086
|
-
*/
|
|
12087
|
-
function refreshComponent(hostLView, componentHostIdx) {
|
|
12088
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12089
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12090
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12091
|
-
if (viewAttachedToChangeDetector(componentView)) {
|
|
12092
|
-
const tView = componentView[TVIEW];
|
|
12093
|
-
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12094
|
-
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12095
|
-
}
|
|
12096
|
-
else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12097
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12098
|
-
refreshContainsDirtyView(componentView);
|
|
12099
|
-
}
|
|
12100
|
-
}
|
|
12101
|
-
}
|
|
12102
|
-
/**
|
|
12103
|
-
* Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
|
|
12104
|
-
* children or descendants of the given lView.
|
|
12105
|
-
*
|
|
12106
|
-
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12107
|
-
*/
|
|
12108
|
-
function refreshContainsDirtyView(lView) {
|
|
12109
|
-
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12110
|
-
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12111
|
-
const embeddedLView = lContainer[i];
|
|
12112
|
-
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12113
|
-
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
|
|
12114
|
-
const embeddedTView = embeddedLView[TVIEW];
|
|
12115
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12116
|
-
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12117
|
-
}
|
|
12118
|
-
else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12119
|
-
refreshContainsDirtyView(embeddedLView);
|
|
12120
|
-
}
|
|
12121
|
-
}
|
|
12122
|
-
}
|
|
12123
|
-
}
|
|
12124
|
-
const tView = lView[TVIEW];
|
|
12125
|
-
// Refresh child component views.
|
|
12126
|
-
const components = tView.components;
|
|
12127
|
-
if (components !== null) {
|
|
12128
|
-
for (let i = 0; i < components.length; i++) {
|
|
12129
|
-
const componentView = getComponentLViewByIndex(components[i], lView);
|
|
12130
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12131
|
-
if (viewAttachedToChangeDetector(componentView) &&
|
|
12132
|
-
componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
|
|
12133
|
-
refreshContainsDirtyView(componentView);
|
|
12134
|
-
}
|
|
12135
|
-
}
|
|
12136
|
-
}
|
|
12137
|
-
}
|
|
12138
|
-
function renderComponent(hostLView, componentHostIdx) {
|
|
12139
|
-
ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
|
|
12140
|
-
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12141
|
-
const componentTView = componentView[TVIEW];
|
|
12142
|
-
syncViewWithBlueprint(componentTView, componentView);
|
|
12143
|
-
const hostRNode = componentView[HOST];
|
|
12144
|
-
// Populate an LView with hydration info retrieved from the DOM via TransferState.
|
|
12145
|
-
if (hostRNode !== null && componentView[HYDRATION] === null) {
|
|
12146
|
-
componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
|
|
12147
|
-
}
|
|
12148
|
-
renderView(componentTView, componentView, componentView[CONTEXT]);
|
|
12149
|
-
}
|
|
12150
|
-
/**
|
|
12151
|
-
* Syncs an LView instance with its blueprint if they have gotten out of sync.
|
|
12152
|
-
*
|
|
12153
|
-
* Typically, blueprints and their view instances should always be in sync, so the loop here
|
|
12154
|
-
* will be skipped. However, consider this case of two components side-by-side:
|
|
12155
|
-
*
|
|
12156
|
-
* App template:
|
|
12157
|
-
* ```
|
|
12158
|
-
* <comp></comp>
|
|
12159
|
-
* <comp></comp>
|
|
12160
|
-
* ```
|
|
12161
|
-
*
|
|
12162
|
-
* The following will happen:
|
|
12163
|
-
* 1. App template begins processing.
|
|
12164
|
-
* 2. First <comp> is matched as a component and its LView is created.
|
|
12165
|
-
* 3. Second <comp> is matched as a component and its LView is created.
|
|
12166
|
-
* 4. App template completes processing, so it's time to check child templates.
|
|
12167
|
-
* 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
|
|
12168
|
-
* 6. Second <comp> template is checked. Its blueprint has been updated by the first
|
|
12169
|
-
* <comp> template, but its LView was created before this update, so it is out of sync.
|
|
12170
|
-
*
|
|
12171
|
-
* Note that embedded views inside ngFor loops will never be out of sync because these views
|
|
12172
|
-
* are processed as soon as they are created.
|
|
12173
|
-
*
|
|
12174
|
-
* @param tView The `TView` that contains the blueprint for syncing
|
|
12175
|
-
* @param lView The view to sync
|
|
12176
|
-
*/
|
|
12177
|
-
function syncViewWithBlueprint(tView, lView) {
|
|
12178
|
-
for (let i = lView.length; i < tView.blueprint.length; i++) {
|
|
12179
|
-
lView.push(tView.blueprint[i]);
|
|
12180
|
-
}
|
|
12181
|
-
}
|
|
12182
|
-
/**
|
|
12183
|
-
* Adds LView or LContainer to the end of the current view tree.
|
|
11855
|
+
* Adds LView or LContainer to the end of the current view tree.
|
|
12184
11856
|
*
|
|
12185
11857
|
* This structure will be used to traverse through nested views to remove listeners
|
|
12186
11858
|
* and call onDestroy callbacks.
|
|
@@ -12207,40 +11879,6 @@ function addToViewTree(lView, lViewOrLContainer) {
|
|
|
12207
11879
|
///////////////////////////////
|
|
12208
11880
|
//// Change detection
|
|
12209
11881
|
///////////////////////////////
|
|
12210
|
-
function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12211
|
-
const rendererFactory = lView[ENVIRONMENT].rendererFactory;
|
|
12212
|
-
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
12213
|
-
// since they were assigned. We do not want to invoke renderer factory functions in that mode
|
|
12214
|
-
// to avoid any possible side-effects.
|
|
12215
|
-
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
|
12216
|
-
if (!checkNoChangesMode && rendererFactory.begin)
|
|
12217
|
-
rendererFactory.begin();
|
|
12218
|
-
try {
|
|
12219
|
-
refreshView(tView, lView, tView.template, context);
|
|
12220
|
-
}
|
|
12221
|
-
catch (error) {
|
|
12222
|
-
if (notifyErrorHandler) {
|
|
12223
|
-
handleError(lView, error);
|
|
12224
|
-
}
|
|
12225
|
-
throw error;
|
|
12226
|
-
}
|
|
12227
|
-
finally {
|
|
12228
|
-
if (!checkNoChangesMode && rendererFactory.end)
|
|
12229
|
-
rendererFactory.end();
|
|
12230
|
-
// One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
|
|
12231
|
-
// other post-order hooks.
|
|
12232
|
-
!checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
|
|
12233
|
-
}
|
|
12234
|
-
}
|
|
12235
|
-
function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
|
|
12236
|
-
setIsInCheckNoChangesMode(true);
|
|
12237
|
-
try {
|
|
12238
|
-
detectChangesInternal(tView, lView, context, notifyErrorHandler);
|
|
12239
|
-
}
|
|
12240
|
-
finally {
|
|
12241
|
-
setIsInCheckNoChangesMode(false);
|
|
12242
|
-
}
|
|
12243
|
-
}
|
|
12244
11882
|
function executeViewQueryFn(flags, viewQueryFn, component) {
|
|
12245
11883
|
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
|
|
12246
11884
|
setCurrentQueryIndex(0);
|
|
@@ -12353,205 +11991,582 @@ function textBindingInternal(lView, index, value) {
|
|
|
12353
11991
|
updateTextNode(lView[RENDERER], element, value);
|
|
12354
11992
|
}
|
|
12355
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
|
+
}
|
|
12356
12006
|
/**
|
|
12357
|
-
*
|
|
12358
|
-
* The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
|
|
12359
|
-
* is injected in a component or directive, the callbacks run when that component or
|
|
12360
|
-
* 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.
|
|
12361
12008
|
*
|
|
12362
|
-
*
|
|
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
|
|
12363
12032
|
*/
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
*/
|
|
12369
|
-
static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
|
|
12370
|
-
/**
|
|
12371
|
-
* @internal
|
|
12372
|
-
* @nocollapse
|
|
12373
|
-
*/
|
|
12374
|
-
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
|
+
}
|
|
12375
12037
|
}
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
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);
|
|
12380
12469
|
}
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
return () => removeLViewOnDestroy(this._lView, callback);
|
|
12470
|
+
finally {
|
|
12471
|
+
leaveView();
|
|
12384
12472
|
}
|
|
12385
12473
|
}
|
|
12386
|
-
function injectDestroyRef() {
|
|
12387
|
-
return new NodeInjectorDestroyRef(getLView());
|
|
12388
|
-
}
|
|
12389
|
-
|
|
12390
12474
|
/**
|
|
12391
|
-
*
|
|
12475
|
+
* Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
|
|
12476
|
+
* them by executing an associated template function.
|
|
12392
12477
|
*/
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
if (!this.all.has(watch)) {
|
|
12402
|
-
return;
|
|
12403
|
-
}
|
|
12404
|
-
this.queue.set(watch, zone);
|
|
12405
|
-
}, allowSignalWrites);
|
|
12406
|
-
this.all.add(watch);
|
|
12407
|
-
// Effects start dirty.
|
|
12408
|
-
watch.notify();
|
|
12409
|
-
let unregisterOnDestroy;
|
|
12410
|
-
const destroy = () => {
|
|
12411
|
-
watch.cleanup();
|
|
12412
|
-
unregisterOnDestroy?.();
|
|
12413
|
-
this.all.delete(watch);
|
|
12414
|
-
this.queue.delete(watch);
|
|
12415
|
-
};
|
|
12416
|
-
unregisterOnDestroy = destroyRef?.onDestroy(destroy);
|
|
12417
|
-
return {
|
|
12418
|
-
destroy,
|
|
12419
|
-
};
|
|
12420
|
-
}
|
|
12421
|
-
flush() {
|
|
12422
|
-
if (this.queue.size === 0) {
|
|
12423
|
-
return;
|
|
12424
|
-
}
|
|
12425
|
-
for (const [watch, zone] of this.queue) {
|
|
12426
|
-
this.queue.delete(watch);
|
|
12427
|
-
if (zone) {
|
|
12428
|
-
zone.run(() => watch.run());
|
|
12429
|
-
}
|
|
12430
|
-
else {
|
|
12431
|
-
watch.run();
|
|
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]);
|
|
12432
12486
|
}
|
|
12433
12487
|
}
|
|
12434
12488
|
}
|
|
12435
|
-
get isQueueEmpty() {
|
|
12436
|
-
return this.queue.size === 0;
|
|
12437
|
-
}
|
|
12438
|
-
/** @nocollapse */
|
|
12439
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
12440
|
-
token: EffectManager,
|
|
12441
|
-
providedIn: 'root',
|
|
12442
|
-
factory: () => new EffectManager(),
|
|
12443
|
-
}); }
|
|
12444
12489
|
}
|
|
12445
12490
|
/**
|
|
12446
|
-
*
|
|
12491
|
+
* Mark transplanted views as needing to be refreshed at their insertion points.
|
|
12447
12492
|
*
|
|
12448
|
-
* @
|
|
12493
|
+
* @param lView The `LView` that may have transplanted views.
|
|
12449
12494
|
*/
|
|
12450
|
-
function
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
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
|
+
}
|
|
12456
12508
|
}
|
|
12457
|
-
|
|
12458
12509
|
/**
|
|
12459
|
-
*
|
|
12460
|
-
*
|
|
12461
|
-
* This function should be called during `firstCreatePass` only.
|
|
12510
|
+
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
|
12462
12511
|
*
|
|
12463
|
-
* @param
|
|
12464
|
-
* @param attrs `TAttributes` containing the styling information.
|
|
12465
|
-
* @param writeToHost Where should the resulting static styles be written?
|
|
12466
|
-
* - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
|
|
12467
|
-
* - `true` Write to `TNode.styles` / `TNode.classes`
|
|
12512
|
+
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12468
12513
|
*/
|
|
12469
|
-
function
|
|
12470
|
-
ngDevMode &&
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
else if (mode == 1 /* AttributeMarker.Classes */) {
|
|
12482
|
-
classes = concatStringsWithSpace(classes, value);
|
|
12483
|
-
}
|
|
12484
|
-
else if (mode == 2 /* AttributeMarker.Styles */) {
|
|
12485
|
-
const style = value;
|
|
12486
|
-
const styleValue = attrs[++i];
|
|
12487
|
-
styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
|
|
12488
|
-
}
|
|
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);
|
|
12489
12526
|
}
|
|
12490
12527
|
}
|
|
12491
|
-
writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
|
|
12492
|
-
writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
|
|
12493
12528
|
}
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
|
|
12507
|
-
|
|
12508
|
-
|
|
12509
|
-
|
|
12510
|
-
if (
|
|
12511
|
-
|
|
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);
|
|
12512
12547
|
}
|
|
12513
|
-
}
|
|
12514
|
-
// When an LContainer is created, the anchor (comment) node is:
|
|
12515
|
-
// - (1) either reused in case of an ElementContainer (<ng-container>)
|
|
12516
|
-
// - (2) or a new comment node is created
|
|
12517
|
-
// In the first case, the anchor comment node would be added to the final
|
|
12518
|
-
// list by the code above (`result.push(unwrapRNode(lNode))`), but the second
|
|
12519
|
-
// case requires extra handling: the anchor node needs to be added to the
|
|
12520
|
-
// final list manually. See additional information in the `createAnchorNode`
|
|
12521
|
-
// function in the `view_container_ref.ts`.
|
|
12522
|
-
//
|
|
12523
|
-
// In the first case, the same reference would be stored in the `NATIVE`
|
|
12524
|
-
// and `HOST` slots in an LContainer. Otherwise, this is the second case and
|
|
12525
|
-
// we should add an element to the final list.
|
|
12526
|
-
if (lNode[NATIVE] !== lNode[HOST]) {
|
|
12527
|
-
result.push(lNode[NATIVE]);
|
|
12528
|
-
}
|
|
12529
|
-
}
|
|
12530
|
-
const tNodeType = tNode.type;
|
|
12531
|
-
if (tNodeType & 8 /* TNodeType.ElementContainer */) {
|
|
12532
|
-
collectNativeNodes(tView, lView, tNode.child, result);
|
|
12533
|
-
}
|
|
12534
|
-
else if (tNodeType & 32 /* TNodeType.Icu */) {
|
|
12535
|
-
const nextRNode = icuContainerIterate(tNode, lView);
|
|
12536
|
-
let rNode;
|
|
12537
|
-
while (rNode = nextRNode()) {
|
|
12538
|
-
result.push(rNode);
|
|
12539
12548
|
}
|
|
12540
12549
|
}
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
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);
|
|
12550
12561
|
}
|
|
12551
12562
|
}
|
|
12552
|
-
tNode = isProjection ? tNode.projectionNext : tNode.next;
|
|
12553
12563
|
}
|
|
12554
|
-
|
|
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
|
+
}
|
|
12555
12570
|
}
|
|
12556
12571
|
|
|
12557
12572
|
class ViewRef$1 {
|
|
@@ -14236,18 +14251,6 @@ function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
|
|
|
14236
14251
|
return ɵɵattributeInterpolateV;
|
|
14237
14252
|
}
|
|
14238
14253
|
|
|
14239
|
-
/**
|
|
14240
|
-
* Synchronously perform change detection on a component (and possibly its sub-components).
|
|
14241
|
-
*
|
|
14242
|
-
* This function triggers change detection in a synchronous way on a component.
|
|
14243
|
-
*
|
|
14244
|
-
* @param component The component which the change detection should be performed on.
|
|
14245
|
-
*/
|
|
14246
|
-
function detectChanges(component) {
|
|
14247
|
-
const view = getComponentViewByInstance(component);
|
|
14248
|
-
detectChangesInternal(view[TVIEW], view, component);
|
|
14249
|
-
}
|
|
14250
|
-
|
|
14251
14254
|
const AT_THIS_LOCATION = '<-- AT THIS LOCATION';
|
|
14252
14255
|
/**
|
|
14253
14256
|
* Retrieves a user friendly string for a given TNodeType for use in
|
|
@@ -14321,9 +14324,16 @@ function validateSiblingNodeExists(node) {
|
|
|
14321
14324
|
/**
|
|
14322
14325
|
* Validates that a node exists or throws
|
|
14323
14326
|
*/
|
|
14324
|
-
function validateNodeExists(node) {
|
|
14327
|
+
function validateNodeExists(node, lView = null, tNode = null) {
|
|
14325
14328
|
if (!node) {
|
|
14326
|
-
|
|
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);
|
|
14327
14337
|
}
|
|
14328
14338
|
}
|
|
14329
14339
|
/**
|
|
@@ -14380,7 +14390,7 @@ function invalidSkipHydrationHost(rNode) {
|
|
|
14380
14390
|
'that doesn\'t act as a component host. Hydration can be ' +
|
|
14381
14391
|
'skipped only on per-component basis.\n\n';
|
|
14382
14392
|
const actual = `${describeDomFromNode(rNode)}\n\n`;
|
|
14383
|
-
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';
|
|
14384
14394
|
const message = header + actual + footer;
|
|
14385
14395
|
return new RuntimeError(-504 /* RuntimeErrorCode.INVALID_SKIP_HYDRATION_HOST */, message);
|
|
14386
14396
|
}
|
|
@@ -14565,8 +14575,9 @@ function getHydrationErrorFooter(componentClassName) {
|
|
|
14565
14575
|
const componentInfo = componentClassName ? `the "${componentClassName}"` : 'corresponding';
|
|
14566
14576
|
return `To fix this problem:\n` +
|
|
14567
14577
|
` * check ${componentInfo} component for hydration-related issues\n` +
|
|
14578
|
+
` * check to see if your template has valid HTML structure\n` +
|
|
14568
14579
|
` * or skip hydration by adding the \`ngSkipHydration\` attribute ` +
|
|
14569
|
-
`to its host node in a template`;
|
|
14580
|
+
`to its host node in a template\n\n`;
|
|
14570
14581
|
}
|
|
14571
14582
|
/**
|
|
14572
14583
|
* An attribute related note for hydration errors
|
|
@@ -14926,17 +14937,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
|
|
|
14926
14937
|
ngDevMode && assertFirstCreatePass(tView);
|
|
14927
14938
|
ngDevMode && ngDevMode.firstCreatePass++;
|
|
14928
14939
|
const tViewConsts = tView.consts;
|
|
14929
|
-
let ssrId = null;
|
|
14930
|
-
const hydrationInfo = lView[HYDRATION];
|
|
14931
|
-
if (hydrationInfo) {
|
|
14932
|
-
const noOffsetIndex = index - HEADER_OFFSET;
|
|
14933
|
-
ssrId = hydrationInfo.data[TEMPLATES]?.[noOffsetIndex] ?? null;
|
|
14934
|
-
}
|
|
14935
14940
|
// TODO(pk): refactor getOrCreateTNode to have the "create" only version
|
|
14936
14941
|
const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
|
|
14937
14942
|
resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
|
|
14938
14943
|
registerPostOrderHooks(tView, tNode);
|
|
14939
|
-
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 */);
|
|
14940
14945
|
if (tView.queries !== null) {
|
|
14941
14946
|
tView.queries.template(tView, tNode);
|
|
14942
14947
|
embeddedTView.queries = tView.queries.embeddedTView(tNode);
|
|
@@ -15003,9 +15008,27 @@ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
|
|
|
15003
15008
|
if (isNodeCreationMode) {
|
|
15004
15009
|
return createContainerAnchorImpl(tView, lView, tNode, index);
|
|
15005
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
|
+
}
|
|
15006
15029
|
// Hydration mode, looking up existing elements in DOM.
|
|
15007
15030
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
15008
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15031
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
15009
15032
|
setSegmentHead(hydrationInfo, index, currentRNode);
|
|
15010
15033
|
const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
|
|
15011
15034
|
const comment = siblingAfter(viewContainerSize, currentRNode);
|
|
@@ -15239,7 +15262,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
|
|
|
15239
15262
|
// `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
|
|
15240
15263
|
// so while processing a `<div>` instruction, point to the next sibling as a
|
|
15241
15264
|
// start of a segment.
|
|
15242
|
-
ngDevMode && validateNodeExists(native.nextSibling);
|
|
15265
|
+
ngDevMode && validateNodeExists(native.nextSibling, lView, tNode);
|
|
15243
15266
|
setSegmentHead(hydrationInfo, index, native.nextSibling);
|
|
15244
15267
|
}
|
|
15245
15268
|
// Checks if the skip hydration attribute is present during hydration so we know to
|
|
@@ -15384,7 +15407,7 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
|
|
|
15384
15407
|
}
|
|
15385
15408
|
// Hydration mode, looking up existing elements in DOM.
|
|
15386
15409
|
const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
15387
|
-
ngDevMode && validateNodeExists(currentRNode);
|
|
15410
|
+
ngDevMode && validateNodeExists(currentRNode, lView, tNode);
|
|
15388
15411
|
const ngContainerSize = getNgContainerSize(hydrationInfo, index);
|
|
15389
15412
|
ngDevMode &&
|
|
15390
15413
|
assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
|
|
@@ -25265,8 +25288,13 @@ class ApplicationInitStatus {
|
|
|
25265
25288
|
this.resolve = res;
|
|
25266
25289
|
this.reject = rej;
|
|
25267
25290
|
});
|
|
25268
|
-
// TODO: Throw RuntimeErrorCode.INVALID_MULTI_PROVIDER if appInits is not an array
|
|
25269
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
|
+
}
|
|
25270
25298
|
}
|
|
25271
25299
|
/** @internal */
|
|
25272
25300
|
runInitializers() {
|
|
@@ -25309,7 +25337,7 @@ class ApplicationInitStatus {
|
|
|
25309
25337
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
|
|
25310
25338
|
type: Injectable,
|
|
25311
25339
|
args: [{ providedIn: 'root' }]
|
|
25312
|
-
}],
|
|
25340
|
+
}], function () { return []; }, null); })();
|
|
25313
25341
|
|
|
25314
25342
|
class Console {
|
|
25315
25343
|
log(message) {
|
|
@@ -26602,6 +26630,7 @@ function createOrReusePlatformInjector(providers = []) {
|
|
|
26602
26630
|
const injector = createPlatformInjector(providers);
|
|
26603
26631
|
_platformInjector = injector;
|
|
26604
26632
|
publishDefaultGlobalUtils();
|
|
26633
|
+
publishSignalConfiguration();
|
|
26605
26634
|
runPlatformInitializers(injector);
|
|
26606
26635
|
return injector;
|
|
26607
26636
|
}
|