From 59b246a00f78a3d73309fdfb1326be2bc13bdcee Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Fri, 17 Jan 2025 17:12:38 +0400 Subject: [PATCH] Fix double rendering of renovated components in ssr mode angular (T1255582) --- .../devextreme-angular/karma.test.shim.js | 2 +- .../devextreme-angular/src/server/render.ts | 12 +- .../src/ui/accordion/index.ts | 1 + .../src/ui/action-sheet/index.ts | 1 + .../src/ui/autocomplete/index.ts | 1 + .../src/ui/bar-gauge/index.ts | 1 + .../devextreme-angular/src/ui/box/index.ts | 1 + .../devextreme-angular/src/ui/bullet/index.ts | 1 + .../src/ui/button-group/index.ts | 1 + .../devextreme-angular/src/ui/button/index.ts | 1 + .../src/ui/calendar/index.ts | 1 + .../devextreme-angular/src/ui/chart/index.ts | 1 + .../devextreme-angular/src/ui/chat/index.ts | 1 + .../src/ui/check-box/index.ts | 1 + .../src/ui/circular-gauge/index.ts | 1 + .../src/ui/color-box/index.ts | 1 + .../src/ui/context-menu/index.ts | 1 + .../src/ui/data-grid/index.ts | 1 + .../src/ui/date-box/index.ts | 1 + .../src/ui/date-range-box/index.ts | 1 + .../src/ui/defer-rendering/index.ts | 1 + .../src/ui/diagram/index.ts | 1 + .../src/ui/draggable/index.ts | 1 + .../devextreme-angular/src/ui/drawer/index.ts | 1 + .../src/ui/drop-down-box/index.ts | 1 + .../src/ui/drop-down-button/index.ts | 1 + .../src/ui/file-manager/index.ts | 1 + .../src/ui/file-uploader/index.ts | 1 + .../src/ui/filter-builder/index.ts | 1 + .../devextreme-angular/src/ui/form/index.ts | 1 + .../devextreme-angular/src/ui/funnel/index.ts | 1 + .../src/ui/gallery/index.ts | 1 + .../devextreme-angular/src/ui/gantt/index.ts | 1 + .../src/ui/html-editor/index.ts | 1 + .../src/ui/linear-gauge/index.ts | 1 + .../devextreme-angular/src/ui/list/index.ts | 1 + .../src/ui/load-indicator/index.ts | 1 + .../src/ui/load-panel/index.ts | 1 + .../devextreme-angular/src/ui/lookup/index.ts | 1 + .../devextreme-angular/src/ui/map/index.ts | 1 + .../devextreme-angular/src/ui/menu/index.ts | 1 + .../src/ui/multi-view/index.ts | 1 + .../src/ui/number-box/index.ts | 1 + .../src/ui/pagination/index.ts | 1 + .../src/ui/pie-chart/index.ts | 1 + .../src/ui/pivot-grid-field-chooser/index.ts | 1 + .../src/ui/pivot-grid/index.ts | 1 + .../src/ui/polar-chart/index.ts | 1 + .../src/ui/popover/index.ts | 1 + .../src/ui/popup/component.ts | 1 + .../src/ui/progress-bar/index.ts | 1 + .../src/ui/radio-group/index.ts | 1 + .../src/ui/range-selector/index.ts | 1 + .../src/ui/range-slider/index.ts | 1 + .../src/ui/recurrence-editor/index.ts | 1 + .../src/ui/resizable/index.ts | 1 + .../src/ui/responsive-box/index.ts | 1 + .../devextreme-angular/src/ui/sankey/index.ts | 1 + .../src/ui/scheduler/index.ts | 1 + .../src/ui/scroll-view/index.ts | 1 + .../src/ui/select-box/index.ts | 1 + .../devextreme-angular/src/ui/slider/index.ts | 1 + .../src/ui/sortable/index.ts | 1 + .../src/ui/sparkline/index.ts | 1 + .../src/ui/speed-dial-action/index.ts | 1 + .../src/ui/splitter/index.ts | 1 + .../devextreme-angular/src/ui/switch/index.ts | 1 + .../src/ui/tab-panel/index.ts | 1 + .../devextreme-angular/src/ui/tabs/index.ts | 1 + .../src/ui/tag-box/index.ts | 1 + .../src/ui/text-area/index.ts | 1 + .../src/ui/text-box/index.ts | 1 + .../src/ui/tile-view/index.ts | 1 + .../devextreme-angular/src/ui/toast/index.ts | 1 + .../src/ui/toolbar/index.ts | 1 + .../src/ui/tooltip/index.ts | 1 + .../src/ui/tree-list/index.ts | 1 + .../src/ui/tree-map/index.ts | 1 + .../src/ui/tree-view/index.ts | 1 + .../src/ui/validation-group/index.ts | 1 + .../src/ui/validation-summary/index.ts | 1 + .../src/ui/validator/index.ts | 1 + .../src/ui/vector-map/index.ts | 1 + .../tests/src/server/hydration.spec.ts | 142 ++++++++++++++++++ 84 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 packages/devextreme-angular/tests/src/server/hydration.spec.ts diff --git a/packages/devextreme-angular/karma.test.shim.js b/packages/devextreme-angular/karma.test.shim.js index 1de98753dd5c..f3e70816c60e 100644 --- a/packages/devextreme-angular/karma.test.shim.js +++ b/packages/devextreme-angular/karma.test.shim.js @@ -8,6 +8,6 @@ testing.TestBed.initTestEnvironment( browser.platformBrowserDynamicTesting(), ); -const context = require.context('./tests/dist', true, /^.\/(?!.*\/ssr-components\.spec.js$).*\.spec\.js$/); +const context = require.context('./tests/dist', true, /^.\/(?!.*\/(ssr-components|hydration)\.spec\.js$).*\.spec\.js$/); context.keys().map(context); __karma__.start(); diff --git a/packages/devextreme-angular/src/server/render.ts b/packages/devextreme-angular/src/server/render.ts index 30bd0f47b3b9..04773ba08834 100644 --- a/packages/devextreme-angular/src/server/render.ts +++ b/packages/devextreme-angular/src/server/render.ts @@ -21,15 +21,21 @@ export class DxServerModule { const el = infernoRenderer.createElement(component, props); const document = container.ownerDocument; const temp = document.createElement(container.tagName); + temp.innerHTML = renderToString(el); + const mainElement = temp.childNodes[0]; const childString = mainElement.innerHTML; for (let i = 0; i < mainElement.attributes.length; i++) { - temp.setAttribute(mainElement.attributes[i].name, mainElement.attributes[i].value); + const attr = mainElement.attributes[i]; + + if (!container.hasAttribute(attr.name)) { + container.setAttribute(attr.name, attr.value); + } } - temp.innerHTML = childString; - container.outerHTML = temp.outerHTML; + + container.innerHTML = childString; }, }); } diff --git a/packages/devextreme-angular/src/ui/accordion/index.ts b/packages/devextreme-angular/src/ui/accordion/index.ts index 81a36a56b982..e404eb1f12cf 100644 --- a/packages/devextreme-angular/src/ui/accordion/index.ts +++ b/packages/devextreme-angular/src/ui/accordion/index.ts @@ -57,6 +57,7 @@ import { DxiAccordionItemComponent } from 'devextreme-angular/ui/accordion/neste @Component({ selector: 'dx-accordion', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/action-sheet/index.ts b/packages/devextreme-angular/src/ui/action-sheet/index.ts index 12cc3b2d1542..a650af858180 100644 --- a/packages/devextreme-angular/src/ui/action-sheet/index.ts +++ b/packages/devextreme-angular/src/ui/action-sheet/index.ts @@ -57,6 +57,7 @@ import { DxiActionSheetItemComponent } from 'devextreme-angular/ui/action-sheet/ @Component({ selector: 'dx-action-sheet', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/autocomplete/index.ts b/packages/devextreme-angular/src/ui/autocomplete/index.ts index f4632412979b..2d1f959ed3fa 100644 --- a/packages/devextreme-angular/src/ui/autocomplete/index.ts +++ b/packages/devextreme-angular/src/ui/autocomplete/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-autocomplete', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/bar-gauge/index.ts b/packages/devextreme-angular/src/ui/bar-gauge/index.ts index 49e6e94b53ce..cf71a5cb6f39 100644 --- a/packages/devextreme-angular/src/ui/bar-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/bar-gauge/index.ts @@ -89,6 +89,7 @@ import { DxoBarGaugeTooltipBorderModule } from 'devextreme-angular/ui/bar-gauge/ selector: 'dx-bar-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/box/index.ts b/packages/devextreme-angular/src/ui/box/index.ts index 818127ee9cd6..4306fade837a 100644 --- a/packages/devextreme-angular/src/ui/box/index.ts +++ b/packages/devextreme-angular/src/ui/box/index.ts @@ -58,6 +58,7 @@ import { DxiBoxItemComponent } from 'devextreme-angular/ui/box/nested'; @Component({ selector: 'dx-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/bullet/index.ts b/packages/devextreme-angular/src/ui/bullet/index.ts index 31b3405d3944..fadcff02e11a 100644 --- a/packages/devextreme-angular/src/ui/bullet/index.ts +++ b/packages/devextreme-angular/src/ui/bullet/index.ts @@ -60,6 +60,7 @@ import { DxoBulletTooltipModule } from 'devextreme-angular/ui/bullet/nested'; selector: 'dx-bullet', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/button-group/index.ts b/packages/devextreme-angular/src/ui/button-group/index.ts index a1b480acbf73..41cc76d66937 100644 --- a/packages/devextreme-angular/src/ui/button-group/index.ts +++ b/packages/devextreme-angular/src/ui/button-group/index.ts @@ -54,6 +54,7 @@ import { DxiButtonGroupItemComponent } from 'devextreme-angular/ui/button-group/ @Component({ selector: 'dx-button-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/button/index.ts b/packages/devextreme-angular/src/ui/button/index.ts index 00ee05e094f7..c6d0f60fd4b3 100644 --- a/packages/devextreme-angular/src/ui/button/index.ts +++ b/packages/devextreme-angular/src/ui/button/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-button', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/calendar/index.ts b/packages/devextreme-angular/src/ui/calendar/index.ts index 1adbabd412d8..eeed5326463a 100644 --- a/packages/devextreme-angular/src/ui/calendar/index.ts +++ b/packages/devextreme-angular/src/ui/calendar/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-calendar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/chart/index.ts b/packages/devextreme-angular/src/ui/chart/index.ts index 048448d40a43..73890a825031 100644 --- a/packages/devextreme-angular/src/ui/chart/index.ts +++ b/packages/devextreme-angular/src/ui/chart/index.ts @@ -242,6 +242,7 @@ import { DxiChartValueAxisComponent } from 'devextreme-angular/ui/chart/nested'; selector: 'dx-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/chat/index.ts b/packages/devextreme-angular/src/ui/chat/index.ts index 45e72c1c25d6..005f873a1778 100644 --- a/packages/devextreme-angular/src/ui/chat/index.ts +++ b/packages/devextreme-angular/src/ui/chat/index.ts @@ -73,6 +73,7 @@ import { DxiChatTypingUserComponent } from 'devextreme-angular/ui/chat/nested'; @Component({ selector: 'dx-chat', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/check-box/index.ts b/packages/devextreme-angular/src/ui/check-box/index.ts index e288e2dbd966..86ca7f18a9e2 100644 --- a/packages/devextreme-angular/src/ui/check-box/index.ts +++ b/packages/devextreme-angular/src/ui/check-box/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-check-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/circular-gauge/index.ts b/packages/devextreme-angular/src/ui/circular-gauge/index.ts index 8fb541bdca3a..793792e89f51 100644 --- a/packages/devextreme-angular/src/ui/circular-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/circular-gauge/index.ts @@ -100,6 +100,7 @@ import { DxoCircularGaugeValueIndicatorModule } from 'devextreme-angular/ui/circ selector: 'dx-circular-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/color-box/index.ts b/packages/devextreme-angular/src/ui/color-box/index.ts index ba5ba3d2310c..ab899508679f 100644 --- a/packages/devextreme-angular/src/ui/color-box/index.ts +++ b/packages/devextreme-angular/src/ui/color-box/index.ts @@ -95,6 +95,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-color-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/context-menu/index.ts b/packages/devextreme-angular/src/ui/context-menu/index.ts index 8942dd9b042e..b977d5273160 100644 --- a/packages/devextreme-angular/src/ui/context-menu/index.ts +++ b/packages/devextreme-angular/src/ui/context-menu/index.ts @@ -88,6 +88,7 @@ import { DxiContextMenuItemComponent } from 'devextreme-angular/ui/context-menu/ @Component({ selector: 'dx-context-menu', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/data-grid/index.ts b/packages/devextreme-angular/src/ui/data-grid/index.ts index aeb6403582ca..5327e0aacab7 100644 --- a/packages/devextreme-angular/src/ui/data-grid/index.ts +++ b/packages/devextreme-angular/src/ui/data-grid/index.ts @@ -219,6 +219,7 @@ import { DxiDataGridSortByGroupSummaryInfoComponent } from 'devextreme-angular/u @Component({ selector: 'dx-data-grid', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/date-box/index.ts b/packages/devextreme-angular/src/ui/date-box/index.ts index edb5a43643a6..200e9c43df79 100644 --- a/packages/devextreme-angular/src/ui/date-box/index.ts +++ b/packages/devextreme-angular/src/ui/date-box/index.ts @@ -102,6 +102,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-date-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/date-range-box/index.ts b/packages/devextreme-angular/src/ui/date-range-box/index.ts index 87bb89e0b8fd..f183d81fe986 100644 --- a/packages/devextreme-angular/src/ui/date-range-box/index.ts +++ b/packages/devextreme-angular/src/ui/date-range-box/index.ts @@ -101,6 +101,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-date-range-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/defer-rendering/index.ts b/packages/devextreme-angular/src/ui/defer-rendering/index.ts index 04d631d6906e..60a1ab626cf8 100644 --- a/packages/devextreme-angular/src/ui/defer-rendering/index.ts +++ b/packages/devextreme-angular/src/ui/defer-rendering/index.ts @@ -63,6 +63,7 @@ import { DxoDeferRenderingToModule } from 'devextreme-angular/ui/defer-rendering @Component({ selector: 'dx-defer-rendering', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/diagram/index.ts b/packages/devextreme-angular/src/ui/diagram/index.ts index a6805f3f9d7c..1b7f51a12727 100644 --- a/packages/devextreme-angular/src/ui/diagram/index.ts +++ b/packages/devextreme-angular/src/ui/diagram/index.ts @@ -103,6 +103,7 @@ import { DxiDiagramCustomShapeComponent } from 'devextreme-angular/ui/diagram/ne @Component({ selector: 'dx-diagram', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/draggable/index.ts b/packages/devextreme-angular/src/ui/draggable/index.ts index 61798be15297..3a8f09d90e43 100644 --- a/packages/devextreme-angular/src/ui/draggable/index.ts +++ b/packages/devextreme-angular/src/ui/draggable/index.ts @@ -46,6 +46,7 @@ import { DxoDraggableCursorOffsetModule } from 'devextreme-angular/ui/draggable/ @Component({ selector: 'dx-draggable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drawer/index.ts b/packages/devextreme-angular/src/ui/drawer/index.ts index a2f08d33ed0e..ea71c4a0de08 100644 --- a/packages/devextreme-angular/src/ui/drawer/index.ts +++ b/packages/devextreme-angular/src/ui/drawer/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-drawer', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drop-down-box/index.ts b/packages/devextreme-angular/src/ui/drop-down-box/index.ts index c771e537ed6b..845ba3e45946 100644 --- a/packages/devextreme-angular/src/ui/drop-down-box/index.ts +++ b/packages/devextreme-angular/src/ui/drop-down-box/index.ts @@ -100,6 +100,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-drop-down-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drop-down-button/index.ts b/packages/devextreme-angular/src/ui/drop-down-button/index.ts index 24c67054b786..353e9c143a56 100644 --- a/packages/devextreme-angular/src/ui/drop-down-button/index.ts +++ b/packages/devextreme-angular/src/ui/drop-down-button/index.ts @@ -83,6 +83,7 @@ import { DxiDropDownButtonItemComponent } from 'devextreme-angular/ui/drop-down- @Component({ selector: 'dx-drop-down-button', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/file-manager/index.ts b/packages/devextreme-angular/src/ui/file-manager/index.ts index 2858ec4b50cf..c74700c1c44f 100644 --- a/packages/devextreme-angular/src/ui/file-manager/index.ts +++ b/packages/devextreme-angular/src/ui/file-manager/index.ts @@ -71,6 +71,7 @@ import { DxoFileManagerUploadModule } from 'devextreme-angular/ui/file-manager/n @Component({ selector: 'dx-file-manager', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/file-uploader/index.ts b/packages/devextreme-angular/src/ui/file-uploader/index.ts index d3d48e667c76..e6ef3d12e0cc 100644 --- a/packages/devextreme-angular/src/ui/file-uploader/index.ts +++ b/packages/devextreme-angular/src/ui/file-uploader/index.ts @@ -61,6 +61,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-file-uploader', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/filter-builder/index.ts b/packages/devextreme-angular/src/ui/filter-builder/index.ts index 076a58661fe9..5b141d117172 100644 --- a/packages/devextreme-angular/src/ui/filter-builder/index.ts +++ b/packages/devextreme-angular/src/ui/filter-builder/index.ts @@ -77,6 +77,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-filter-builder', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/form/index.ts b/packages/devextreme-angular/src/ui/form/index.ts index 54a17cfc40b6..72bb398cb28a 100644 --- a/packages/devextreme-angular/src/ui/form/index.ts +++ b/packages/devextreme-angular/src/ui/form/index.ts @@ -86,6 +86,7 @@ import { DxiFormTabbedItemComponent } from 'devextreme-angular/ui/form/nested'; @Component({ selector: 'dx-form', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/funnel/index.ts b/packages/devextreme-angular/src/ui/funnel/index.ts index c691dba9fc12..9ebf1370ffa5 100644 --- a/packages/devextreme-angular/src/ui/funnel/index.ts +++ b/packages/devextreme-angular/src/ui/funnel/index.ts @@ -100,6 +100,7 @@ import { DxoFunnelTooltipBorderModule } from 'devextreme-angular/ui/funnel/neste selector: 'dx-funnel', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/gallery/index.ts b/packages/devextreme-angular/src/ui/gallery/index.ts index c54c57a1f831..d5825c1ea907 100644 --- a/packages/devextreme-angular/src/ui/gallery/index.ts +++ b/packages/devextreme-angular/src/ui/gallery/index.ts @@ -57,6 +57,7 @@ import { DxiGalleryItemComponent } from 'devextreme-angular/ui/gallery/nested'; @Component({ selector: 'dx-gallery', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/gantt/index.ts b/packages/devextreme-angular/src/ui/gantt/index.ts index d5fbdbcc2a05..c79e41e0d8c7 100644 --- a/packages/devextreme-angular/src/ui/gantt/index.ts +++ b/packages/devextreme-angular/src/ui/gantt/index.ts @@ -101,6 +101,7 @@ import { DxiGanttStripLineComponent } from 'devextreme-angular/ui/gantt/nested'; @Component({ selector: 'dx-gantt', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/html-editor/index.ts b/packages/devextreme-angular/src/ui/html-editor/index.ts index 285afb6cbafe..cbbf7d9dcfc7 100644 --- a/packages/devextreme-angular/src/ui/html-editor/index.ts +++ b/packages/devextreme-angular/src/ui/html-editor/index.ts @@ -88,6 +88,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-html-editor', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/linear-gauge/index.ts b/packages/devextreme-angular/src/ui/linear-gauge/index.ts index 1e5c288ef831..6ed91b5cff7c 100644 --- a/packages/devextreme-angular/src/ui/linear-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/linear-gauge/index.ts @@ -102,6 +102,7 @@ import { DxoLinearGaugeWidthModule } from 'devextreme-angular/ui/linear-gauge/ne selector: 'dx-linear-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/list/index.ts b/packages/devextreme-angular/src/ui/list/index.ts index 38f29c54af5a..def7747fd2d3 100644 --- a/packages/devextreme-angular/src/ui/list/index.ts +++ b/packages/devextreme-angular/src/ui/list/index.ts @@ -74,6 +74,7 @@ import { DxiListMenuItemComponent } from 'devextreme-angular/ui/list/nested'; @Component({ selector: 'dx-list', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/load-indicator/index.ts b/packages/devextreme-angular/src/ui/load-indicator/index.ts index 0265b2f66fb2..6d7477c7783e 100644 --- a/packages/devextreme-angular/src/ui/load-indicator/index.ts +++ b/packages/devextreme-angular/src/ui/load-indicator/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-load-indicator', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/load-panel/index.ts b/packages/devextreme-angular/src/ui/load-panel/index.ts index 95fb08fa0afc..dc7dc80ab50f 100644 --- a/packages/devextreme-angular/src/ui/load-panel/index.ts +++ b/packages/devextreme-angular/src/ui/load-panel/index.ts @@ -68,6 +68,7 @@ import { DxoLoadPanelToModule } from 'devextreme-angular/ui/load-panel/nested'; @Component({ selector: 'dx-load-panel', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/lookup/index.ts b/packages/devextreme-angular/src/ui/lookup/index.ts index 15852d5613af..409e7ed9ffdb 100644 --- a/packages/devextreme-angular/src/ui/lookup/index.ts +++ b/packages/devextreme-angular/src/ui/lookup/index.ts @@ -100,6 +100,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-lookup', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/map/index.ts b/packages/devextreme-angular/src/ui/map/index.ts index 919c377791f5..ade40d3399ef 100644 --- a/packages/devextreme-angular/src/ui/map/index.ts +++ b/packages/devextreme-angular/src/ui/map/index.ts @@ -69,6 +69,7 @@ import { DxiMapRouteComponent } from 'devextreme-angular/ui/map/nested'; @Component({ selector: 'dx-map', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/menu/index.ts b/packages/devextreme-angular/src/ui/menu/index.ts index 0ffef247a2bf..e4c225e69186 100644 --- a/packages/devextreme-angular/src/ui/menu/index.ts +++ b/packages/devextreme-angular/src/ui/menu/index.ts @@ -87,6 +87,7 @@ import { DxiMenuItemComponent } from 'devextreme-angular/ui/menu/nested'; @Component({ selector: 'dx-menu', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/multi-view/index.ts b/packages/devextreme-angular/src/ui/multi-view/index.ts index e909854fc039..9f754456de49 100644 --- a/packages/devextreme-angular/src/ui/multi-view/index.ts +++ b/packages/devextreme-angular/src/ui/multi-view/index.ts @@ -57,6 +57,7 @@ import { DxiMultiViewItemComponent } from 'devextreme-angular/ui/multi-view/nest @Component({ selector: 'dx-multi-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/number-box/index.ts b/packages/devextreme-angular/src/ui/number-box/index.ts index c509986e3ecd..624c85ba85e9 100644 --- a/packages/devextreme-angular/src/ui/number-box/index.ts +++ b/packages/devextreme-angular/src/ui/number-box/index.ts @@ -71,6 +71,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-number-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pagination/index.ts b/packages/devextreme-angular/src/ui/pagination/index.ts index 9dff7b407b9f..9f3f483386e4 100644 --- a/packages/devextreme-angular/src/ui/pagination/index.ts +++ b/packages/devextreme-angular/src/ui/pagination/index.ts @@ -48,6 +48,7 @@ import { @Component({ selector: 'dx-pagination', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pie-chart/index.ts b/packages/devextreme-angular/src/ui/pie-chart/index.ts index f239534a4e70..30860d51ba04 100644 --- a/packages/devextreme-angular/src/ui/pie-chart/index.ts +++ b/packages/devextreme-angular/src/ui/pie-chart/index.ts @@ -123,6 +123,7 @@ import { DxiPieChartSeriesComponent } from 'devextreme-angular/ui/pie-chart/nest selector: 'dx-pie-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts b/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts index e07b7e51a860..1ccbfaa197ed 100644 --- a/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts +++ b/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts @@ -58,6 +58,7 @@ import { DxoPivotGridFieldChooserTextsModule } from 'devextreme-angular/ui/pivot @Component({ selector: 'dx-pivot-grid-field-chooser', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pivot-grid/index.ts b/packages/devextreme-angular/src/ui/pivot-grid/index.ts index bf37de7fa9af..6258e1745313 100644 --- a/packages/devextreme-angular/src/ui/pivot-grid/index.ts +++ b/packages/devextreme-angular/src/ui/pivot-grid/index.ts @@ -73,6 +73,7 @@ import { DxoPivotGridTextsModule } from 'devextreme-angular/ui/pivot-grid/nested @Component({ selector: 'dx-pivot-grid', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/polar-chart/index.ts b/packages/devextreme-angular/src/ui/polar-chart/index.ts index e65ad00b807b..01f1ab2157f8 100644 --- a/packages/devextreme-angular/src/ui/polar-chart/index.ts +++ b/packages/devextreme-angular/src/ui/polar-chart/index.ts @@ -180,6 +180,7 @@ import { DxiPolarChartSeriesComponent } from 'devextreme-angular/ui/polar-chart/ selector: 'dx-polar-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/popover/index.ts b/packages/devextreme-angular/src/ui/popover/index.ts index 7a4745572cd0..fb6c2d18600d 100644 --- a/packages/devextreme-angular/src/ui/popover/index.ts +++ b/packages/devextreme-angular/src/ui/popover/index.ts @@ -81,6 +81,7 @@ import { DxiPopoverToolbarItemComponent } from 'devextreme-angular/ui/popover/ne @Component({ selector: 'dx-popover', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/popup/component.ts b/packages/devextreme-angular/src/ui/popup/component.ts index a4c829ea810e..6b875e04256e 100644 --- a/packages/devextreme-angular/src/ui/popup/component.ts +++ b/packages/devextreme-angular/src/ui/popup/component.ts @@ -77,6 +77,7 @@ import { DxiPopupToolbarItemComponent } from 'devextreme-angular/ui/popup/nested @Component({ selector: 'dx-popup', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/progress-bar/index.ts b/packages/devextreme-angular/src/ui/progress-bar/index.ts index 3f044ff271fd..2163cc0b929d 100644 --- a/packages/devextreme-angular/src/ui/progress-bar/index.ts +++ b/packages/devextreme-angular/src/ui/progress-bar/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-progress-bar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/radio-group/index.ts b/packages/devextreme-angular/src/ui/radio-group/index.ts index 7b42ebf1af15..9415b045c3aa 100644 --- a/packages/devextreme-angular/src/ui/radio-group/index.ts +++ b/packages/devextreme-angular/src/ui/radio-group/index.ts @@ -70,6 +70,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-radio-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/range-selector/index.ts b/packages/devextreme-angular/src/ui/range-selector/index.ts index 67a0615b7a5f..ae2e732fc709 100644 --- a/packages/devextreme-angular/src/ui/range-selector/index.ts +++ b/packages/devextreme-angular/src/ui/range-selector/index.ts @@ -199,6 +199,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { selector: 'dx-range-selector', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/range-slider/index.ts b/packages/devextreme-angular/src/ui/range-slider/index.ts index b32fd8c57c62..519e4a27ac24 100644 --- a/packages/devextreme-angular/src/ui/range-slider/index.ts +++ b/packages/devextreme-angular/src/ui/range-slider/index.ts @@ -67,6 +67,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-range-slider', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/recurrence-editor/index.ts b/packages/devextreme-angular/src/ui/recurrence-editor/index.ts index 9ac1c162f741..72e8f7288680 100644 --- a/packages/devextreme-angular/src/ui/recurrence-editor/index.ts +++ b/packages/devextreme-angular/src/ui/recurrence-editor/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-recurrence-editor', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/resizable/index.ts b/packages/devextreme-angular/src/ui/resizable/index.ts index fc96dbd393b9..631898d4b2e1 100644 --- a/packages/devextreme-angular/src/ui/resizable/index.ts +++ b/packages/devextreme-angular/src/ui/resizable/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-resizable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/responsive-box/index.ts b/packages/devextreme-angular/src/ui/responsive-box/index.ts index c8d1a438287b..e57ebba263f2 100644 --- a/packages/devextreme-angular/src/ui/responsive-box/index.ts +++ b/packages/devextreme-angular/src/ui/responsive-box/index.ts @@ -67,6 +67,7 @@ import { DxiResponsiveBoxRowComponent } from 'devextreme-angular/ui/responsive-b @Component({ selector: 'dx-responsive-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sankey/index.ts b/packages/devextreme-angular/src/ui/sankey/index.ts index 84c56ba43dfb..c638513ef740 100644 --- a/packages/devextreme-angular/src/ui/sankey/index.ts +++ b/packages/devextreme-angular/src/ui/sankey/index.ts @@ -90,6 +90,7 @@ import { DxoSankeyTooltipBorderModule } from 'devextreme-angular/ui/sankey/neste selector: 'dx-sankey', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/scheduler/index.ts b/packages/devextreme-angular/src/ui/scheduler/index.ts index 9b7508e9b215..752982153ff1 100644 --- a/packages/devextreme-angular/src/ui/scheduler/index.ts +++ b/packages/devextreme-angular/src/ui/scheduler/index.ts @@ -71,6 +71,7 @@ import { DxiSchedulerViewComponent } from 'devextreme-angular/ui/scheduler/neste @Component({ selector: 'dx-scheduler', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/scroll-view/index.ts b/packages/devextreme-angular/src/ui/scroll-view/index.ts index 569a548556d9..7b8e398b5b21 100644 --- a/packages/devextreme-angular/src/ui/scroll-view/index.ts +++ b/packages/devextreme-angular/src/ui/scroll-view/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-scroll-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/select-box/index.ts b/packages/devextreme-angular/src/ui/select-box/index.ts index 1396860a1366..d1ad19e534a1 100644 --- a/packages/devextreme-angular/src/ui/select-box/index.ts +++ b/packages/devextreme-angular/src/ui/select-box/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-select-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/slider/index.ts b/packages/devextreme-angular/src/ui/slider/index.ts index e358987f24fb..f291b731df75 100644 --- a/packages/devextreme-angular/src/ui/slider/index.ts +++ b/packages/devextreme-angular/src/ui/slider/index.ts @@ -67,6 +67,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-slider', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sortable/index.ts b/packages/devextreme-angular/src/ui/sortable/index.ts index 345f5819d19b..a2a0ffc65e34 100644 --- a/packages/devextreme-angular/src/ui/sortable/index.ts +++ b/packages/devextreme-angular/src/ui/sortable/index.ts @@ -46,6 +46,7 @@ import { DxoSortableCursorOffsetModule } from 'devextreme-angular/ui/sortable/ne @Component({ selector: 'dx-sortable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sparkline/index.ts b/packages/devextreme-angular/src/ui/sparkline/index.ts index daa6feffe5a6..7460f35df156 100644 --- a/packages/devextreme-angular/src/ui/sparkline/index.ts +++ b/packages/devextreme-angular/src/ui/sparkline/index.ts @@ -67,6 +67,7 @@ import { DxoSparklineTooltipModule } from 'devextreme-angular/ui/sparkline/neste selector: 'dx-sparkline', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/speed-dial-action/index.ts b/packages/devextreme-angular/src/ui/speed-dial-action/index.ts index 5c680f51653f..462d82de287c 100644 --- a/packages/devextreme-angular/src/ui/speed-dial-action/index.ts +++ b/packages/devextreme-angular/src/ui/speed-dial-action/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-speed-dial-action', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/splitter/index.ts b/packages/devextreme-angular/src/ui/splitter/index.ts index c3b9a04367b7..ac9f3aab32a1 100644 --- a/packages/devextreme-angular/src/ui/splitter/index.ts +++ b/packages/devextreme-angular/src/ui/splitter/index.ts @@ -59,6 +59,7 @@ import { DxiSplitterItemComponent } from 'devextreme-angular/ui/splitter/nested' @Component({ selector: 'dx-splitter', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/switch/index.ts b/packages/devextreme-angular/src/ui/switch/index.ts index b453ec276451..9cef3bc96635 100644 --- a/packages/devextreme-angular/src/ui/switch/index.ts +++ b/packages/devextreme-angular/src/ui/switch/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-switch', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tab-panel/index.ts b/packages/devextreme-angular/src/ui/tab-panel/index.ts index 163c431209ba..04e24e97c250 100644 --- a/packages/devextreme-angular/src/ui/tab-panel/index.ts +++ b/packages/devextreme-angular/src/ui/tab-panel/index.ts @@ -58,6 +58,7 @@ import { DxiTabPanelItemComponent } from 'devextreme-angular/ui/tab-panel/nested @Component({ selector: 'dx-tab-panel', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tabs/index.ts b/packages/devextreme-angular/src/ui/tabs/index.ts index 1ee3fd6f8d4c..c6609babb77d 100644 --- a/packages/devextreme-angular/src/ui/tabs/index.ts +++ b/packages/devextreme-angular/src/ui/tabs/index.ts @@ -58,6 +58,7 @@ import { DxiTabsItemComponent } from 'devextreme-angular/ui/tabs/nested'; @Component({ selector: 'dx-tabs', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tag-box/index.ts b/packages/devextreme-angular/src/ui/tag-box/index.ts index 49e58d3ed0ec..fa64b6cfb483 100644 --- a/packages/devextreme-angular/src/ui/tag-box/index.ts +++ b/packages/devextreme-angular/src/ui/tag-box/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-tag-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/text-area/index.ts b/packages/devextreme-angular/src/ui/text-area/index.ts index 0673d72a6986..329494d95994 100644 --- a/packages/devextreme-angular/src/ui/text-area/index.ts +++ b/packages/devextreme-angular/src/ui/text-area/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-text-area', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/text-box/index.ts b/packages/devextreme-angular/src/ui/text-box/index.ts index 7c5b428836fa..0b59dd7524c5 100644 --- a/packages/devextreme-angular/src/ui/text-box/index.ts +++ b/packages/devextreme-angular/src/ui/text-box/index.ts @@ -68,6 +68,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-text-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tile-view/index.ts b/packages/devextreme-angular/src/ui/tile-view/index.ts index 3460de39418c..f10d10fff6d2 100644 --- a/packages/devextreme-angular/src/ui/tile-view/index.ts +++ b/packages/devextreme-angular/src/ui/tile-view/index.ts @@ -58,6 +58,7 @@ import { DxiTileViewItemComponent } from 'devextreme-angular/ui/tile-view/nested @Component({ selector: 'dx-tile-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/toast/index.ts b/packages/devextreme-angular/src/ui/toast/index.ts index 161fd1e18d51..71aa90ea233c 100644 --- a/packages/devextreme-angular/src/ui/toast/index.ts +++ b/packages/devextreme-angular/src/ui/toast/index.ts @@ -67,6 +67,7 @@ import { DxoToastToModule } from 'devextreme-angular/ui/toast/nested'; @Component({ selector: 'dx-toast', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/toolbar/index.ts b/packages/devextreme-angular/src/ui/toolbar/index.ts index 168985396718..ce3e64eeae39 100644 --- a/packages/devextreme-angular/src/ui/toolbar/index.ts +++ b/packages/devextreme-angular/src/ui/toolbar/index.ts @@ -57,6 +57,7 @@ import { DxiToolbarItemComponent } from 'devextreme-angular/ui/toolbar/nested'; @Component({ selector: 'dx-toolbar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tooltip/index.ts b/packages/devextreme-angular/src/ui/tooltip/index.ts index eac27fa9a018..8b73b18e3217 100644 --- a/packages/devextreme-angular/src/ui/tooltip/index.ts +++ b/packages/devextreme-angular/src/ui/tooltip/index.ts @@ -72,6 +72,7 @@ import { DxoTooltipToModule } from 'devextreme-angular/ui/tooltip/nested'; @Component({ selector: 'dx-tooltip', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-list/index.ts b/packages/devextreme-angular/src/ui/tree-list/index.ts index 9ff5afa488ac..36db2745505d 100644 --- a/packages/devextreme-angular/src/ui/tree-list/index.ts +++ b/packages/devextreme-angular/src/ui/tree-list/index.ts @@ -195,6 +195,7 @@ import { DxiTreeListColumnComponent } from 'devextreme-angular/ui/tree-list/nest @Component({ selector: 'dx-tree-list', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-map/index.ts b/packages/devextreme-angular/src/ui/tree-map/index.ts index 265d37a315e2..0050c51fad0c 100644 --- a/packages/devextreme-angular/src/ui/tree-map/index.ts +++ b/packages/devextreme-angular/src/ui/tree-map/index.ts @@ -92,6 +92,7 @@ import { DxoTreeMapTreeMapborderModule } from 'devextreme-angular/ui/tree-map/ne selector: 'dx-tree-map', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-view/index.ts b/packages/devextreme-angular/src/ui/tree-view/index.ts index 9ece7413ac99..672f033b0eec 100644 --- a/packages/devextreme-angular/src/ui/tree-view/index.ts +++ b/packages/devextreme-angular/src/ui/tree-view/index.ts @@ -65,6 +65,7 @@ import { DxiTreeViewItemComponent } from 'devextreme-angular/ui/tree-view/nested @Component({ selector: 'dx-tree-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validation-group/index.ts b/packages/devextreme-angular/src/ui/validation-group/index.ts index 75da65aa2bff..e16f0c502cdd 100644 --- a/packages/devextreme-angular/src/ui/validation-group/index.ts +++ b/packages/devextreme-angular/src/ui/validation-group/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-validation-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validation-summary/index.ts b/packages/devextreme-angular/src/ui/validation-summary/index.ts index 9b83f40b5e58..dcfea468784d 100644 --- a/packages/devextreme-angular/src/ui/validation-summary/index.ts +++ b/packages/devextreme-angular/src/ui/validation-summary/index.ts @@ -55,6 +55,7 @@ import { DxiValidationSummaryItemComponent } from 'devextreme-angular/ui/validat @Component({ selector: 'dx-validation-summary', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validator/index.ts b/packages/devextreme-angular/src/ui/validator/index.ts index 7b8ee81b4a9d..3feb9ee6889b 100644 --- a/packages/devextreme-angular/src/ui/validator/index.ts +++ b/packages/devextreme-angular/src/ui/validator/index.ts @@ -77,6 +77,7 @@ import { DxiValidatorValidationRuleComponent } from 'devextreme-angular/ui/valid @Component({ selector: 'dx-validator', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/vector-map/index.ts b/packages/devextreme-angular/src/ui/vector-map/index.ts index 943cd352c788..d0361b7cd0e1 100644 --- a/packages/devextreme-angular/src/ui/vector-map/index.ts +++ b/packages/devextreme-angular/src/ui/vector-map/index.ts @@ -108,6 +108,7 @@ import { DxiVectorMapLegendComponent } from 'devextreme-angular/ui/vector-map/ne selector: 'dx-vector-map', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/tests/src/server/hydration.spec.ts b/packages/devextreme-angular/tests/src/server/hydration.spec.ts new file mode 100644 index 000000000000..092bed8c6d5e --- /dev/null +++ b/packages/devextreme-angular/tests/src/server/hydration.spec.ts @@ -0,0 +1,142 @@ +import { BrowserModule, provideClientHydration } from '@angular/platform-browser'; +import { Component, destroyPlatform, NgModule, PLATFORM_ID, VERSION, importProvidersFrom } from '@angular/core'; +import { provideServerRendering, ServerModule } from "@angular/platform-server"; +import { DxServerModule } from "devextreme-angular/server"; +import infernoRenderer from 'devextreme/core/inferno_renderer'; +import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; +import { DevExtremeModule } from "devextreme-angular"; +import { componentNames } from './component-names'; + +const containerClass = 'container'; +const containerSelector = `.${containerClass}`; + +@Component({ + selector: 'app-root', + template: `
+ ${componentNames.map((name) => ``).join('\n')} +
`, +}) +class AppComponent {} + +@NgModule({ + declarations: [AppComponent], + imports: [BrowserModule, DevExtremeModule], + bootstrap: [AppComponent], + providers: [provideClientHydration()], +}) +class AppBrowserModule {} + +@NgModule({ + declarations: [AppComponent], + imports: [ServerModule, DevExtremeModule], + bootstrap: [AppComponent], + providers: [ + provideClientHydration(), + provideServerRendering(), + { provide: PLATFORM_ID, useValue: 'server' }, + importProvidersFrom(DxServerModule) + ], +}) +class AppSSRModule {} + +class TestHelpers { + static createSSRBodyMarkup(ssrComponentsHTML: string): string { + const nghData = '[{}]'; + return `${ssrComponentsHTML} + `; + } + + static normalizeClassNames(element: HTMLElement): void { + const classNames = Array.from(element.classList).sort(); + // @ts-ignore + element.classList.remove(...element.classList); + element.classList.add(...classNames); + } + + static compareContainers(ssrContainer: HTMLElement, hydratedContainer: HTMLElement): [string, string] { + const selector = `${containerSelector} > *`; + + [ssrContainer, hydratedContainer].forEach(container => { + container.querySelectorAll(selector).forEach(el => { + this.normalizeClassNames(el as HTMLElement); + }); + }); + + return [ssrContainer.innerHTML, hydratedContainer.innerHTML]; + } + + static hasConsoleMessage(spy: jasmine.Spy, messages: string[]): boolean { + return spy.calls.allArgs().some(args => + messages.some(msg => args[0].toLowerCase().includes(msg.toLowerCase())) + ); + } +} + +describe('Angular Components Hydration Test', () => { + let consoleSpies: { + warn: jasmine.Spy; + error: jasmine.Spy; + log: jasmine.Spy; + }; + let ssrState: { + body: HTMLElement | null; + containerHtml: string; + } = { + body: null, + containerHtml: '' + }; + + beforeAll(() => { + consoleSpies = { + warn: spyOn(console, 'warn').and.callThrough(), + error: spyOn(console, 'error').and.callThrough(), + log: spyOn(console, 'log').and.callThrough() + }; + }); + + beforeEach(() => { + destroyPlatform(); + }); + + afterEach(() => { + expect(consoleSpies.error).not.toHaveBeenCalled(); + expect(TestHelpers.hasConsoleMessage( + consoleSpies.warn, ['exception', 'hydration']) + ).toBeFalsy(); + }); + + it('should generate correct SSR HTML', async () => { + document.body.innerHTML = ''; + + // Act + await platformBrowserDynamic().bootstrapModule(AppSSRModule); + + // Assert + ssrState.body = document.body; + ssrState.containerHtml = document.querySelector(`${containerSelector}`)?.outerHTML ?? ''; + + expect(ssrState.containerHtml).toBeTruthy(); + }); + + it('should correctly hydrate server-rendered HTML', async () => { + infernoRenderer.resetInjection(); + document.body.innerHTML = TestHelpers.createSSRBodyMarkup(ssrState.containerHtml); + + // Act + await platformBrowserDynamic().bootstrapModule(AppBrowserModule); + + // Assert + const [ssrResult, hydratedResult] = TestHelpers.compareContainers( + ssrState.body.querySelector(`${containerSelector}`), + document.querySelector(`${containerSelector}`) + ); + + expect(TestHelpers.hasConsoleMessage( + consoleSpies.log, + ['Angular hydrated 1 component(s) and 77 node(s), 75 component(s) were skipped'] + ) + ).toBeTruthy(); + + expect(ssrResult).toEqual(hydratedResult); + }); +});