Skip to content

Commit a70a682

Browse files
authored
fix(module:water-mark): make server-side compatible (#9250)
1 parent 57535d5 commit a70a682

2 files changed

Lines changed: 67 additions & 21 deletions

File tree

components/water-mark/water-mark.component.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
44
*/
55

6+
import { isPlatformServer } from '@angular/common';
67
import {
7-
AfterViewInit,
8+
afterNextRender,
89
ChangeDetectionStrategy,
910
ChangeDetectorRef,
1011
Component,
@@ -16,6 +17,7 @@ import {
1617
numberAttribute,
1718
OnChanges,
1819
OnInit,
20+
PLATFORM_ID,
1921
SimpleChanges
2022
} from '@angular/core';
2123

@@ -38,7 +40,7 @@ const FontGap = 3;
3840
class: 'ant-water-mark'
3941
}
4042
})
41-
export class NzWaterMarkComponent implements AfterViewInit, OnInit, OnChanges {
43+
export class NzWaterMarkComponent implements OnInit, OnChanges {
4244
@Input({ transform: numberAttribute }) nzWidth: number = 120;
4345
@Input({ transform: numberAttribute }) nzHeight: number = 64;
4446
@Input({ transform: numberAttribute }) nzRotate: number = -22;
@@ -49,44 +51,49 @@ export class NzWaterMarkComponent implements AfterViewInit, OnInit, OnChanges {
4951
@Input() nzGap: [number, number] = [100, 100];
5052
@Input() nzOffset: [number, number] = [this.nzGap[0] / 2, this.nzGap[1] / 2];
5153

54+
private isServer = isPlatformServer(inject(PLATFORM_ID));
55+
5256
private document: Document = inject(DOCUMENT);
5357
private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;
5458
private cdr: ChangeDetectorRef = inject(ChangeDetectorRef);
55-
private destroyRef = inject(DestroyRef);
5659

5760
waterMarkElement: HTMLDivElement = this.document.createElement('div');
5861
stopObservation: boolean = false;
5962

60-
observer = new MutationObserver(mutations => {
61-
if (this.stopObservation) {
63+
private observer: MutationObserver | null = null;
64+
65+
constructor() {
66+
if (this.isServer) {
6267
return;
6368
}
64-
mutations.forEach(mutation => {
65-
if (reRendering(mutation, this.waterMarkElement)) {
66-
this.destroyWatermark();
67-
this.renderWatermark();
69+
70+
const observer = (this.observer = new MutationObserver(mutations => {
71+
if (this.stopObservation) {
72+
return;
6873
}
74+
mutations.forEach(mutation => {
75+
if (reRendering(mutation, this.waterMarkElement)) {
76+
this.destroyWatermark();
77+
this.renderWatermark();
78+
}
79+
});
80+
}));
81+
82+
afterNextRender(() => {
83+
this.renderWatermark();
6984
});
70-
});
7185

72-
constructor() {
73-
this.destroyRef.onDestroy(() => {
74-
this.observer.disconnect();
75-
});
86+
inject(DestroyRef).onDestroy(() => observer.disconnect());
7687
}
7788

7889
ngOnInit(): void {
79-
this.observer.observe(this.el, {
90+
this.observer?.observe(this.el, {
8091
subtree: true,
8192
childList: true,
8293
attributeFilter: ['style', 'class']
8394
});
8495
}
8596

86-
ngAfterViewInit(): void {
87-
this.renderWatermark();
88-
}
89-
9097
ngOnChanges(changes: SimpleChanges): void {
9198
const { nzRotate, nzZIndex, nzWidth, nzHeight, nzImage, nzContent, nzFont, gapX, gapY, offsetLeft, offsetTop } =
9299
changes;
@@ -228,6 +235,10 @@ export class NzWaterMarkComponent implements AfterViewInit, OnInit, OnChanges {
228235
}
229236

230237
renderWatermark(): void {
238+
if (this.isServer) {
239+
return;
240+
}
241+
231242
if (!this.nzContent && !this.nzImage) {
232243
return;
233244
}

components/water-mark/water-mark.spec.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
44
*/
55

6-
import { Component, DebugElement } from '@angular/core';
6+
import { ApplicationRef, Component, DebugElement, destroyPlatform } from '@angular/core';
77
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
8-
import { By } from '@angular/platform-browser';
8+
import { bootstrapApplication, By } from '@angular/platform-browser';
9+
import { renderApplication } from '@angular/platform-server';
10+
11+
import { NzSafeAny } from 'ng-zorro-antd/core/types';
912

1013
import { FontType } from './typings';
1114
import { NzWaterMarkComponent } from './water-mark.component';
@@ -85,7 +88,39 @@ describe('water-mark', () => {
8588
}));
8689
});
8790

91+
describe('water-mark (SSR)', () => {
92+
it('should render water mark on server', async () => {
93+
destroyPlatform();
94+
95+
// `as any` because `ngDevMode` is not exposed on the global namespace typings.
96+
const ngDevMode = (globalThis as NzSafeAny)['ngDevMode'];
97+
98+
try {
99+
// Disable development-mode checks for these tests (we don't care).
100+
(globalThis as NzSafeAny)['ngDevMode'] = false;
101+
// Enter server mode for the duration of this function.
102+
globalThis['ngServerMode'] = true;
103+
104+
const bootstrap = (): Promise<ApplicationRef> =>
105+
bootstrapApplication(NzTestWaterMarkBasicComponent, { providers: [] });
106+
const html = await renderApplication(bootstrap, {
107+
document: '<html><head></head><body><nz-app></nz-app></body></html>'
108+
});
109+
110+
expect(html).toContain('<nz-water-mark class="ant-water-mark water-mark">');
111+
} finally {
112+
// Restore the original value.
113+
(globalThis as NzSafeAny)['ngDevMode'] = ngDevMode;
114+
// Leave server mode so the remaining test is back in "client mode".
115+
globalThis['ngServerMode'] = undefined;
116+
}
117+
118+
destroyPlatform();
119+
});
120+
});
121+
88122
@Component({
123+
selector: 'nz-app',
89124
imports: [NzWaterMarkModule],
90125
template: `
91126
<nz-water-mark

0 commit comments

Comments
 (0)