Skip to content

Commit c79c203

Browse files
refactor: migrate to standard decorators (#8739)
1 parent 5779804 commit c79c203

File tree

23 files changed

+127
-101
lines changed

23 files changed

+127
-101
lines changed

components/affix/affix.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ export class NzAffixComponent implements AfterViewInit, OnChanges, OnDestroy, On
6262
@Input() nzTarget?: string | Element | Window;
6363

6464
@Input({ transform: numberAttributeWithZeroFallback })
65-
@WithConfig<number | null>()
65+
@WithConfig()
6666
nzOffsetTop?: null | number;
6767

6868
@Input({ transform: numberAttributeWithZeroFallback })
69-
@WithConfig<number | null>()
69+
@WithConfig()
7070
nzOffsetBottom?: null | number;
7171

7272
@Output() readonly nzChange = new EventEmitter<boolean>();

components/anchor/anchor.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
9797
nzBounds: number = 5;
9898

9999
@Input({ transform: numberAttributeWithZeroFallback })
100-
@WithConfig<number>()
100+
@WithConfig()
101101
nzOffsetTop?: number = undefined;
102102

103103
@Input({ transform: numberAttributeWithZeroFallback })
104-
@WithConfig<number>()
104+
@WithConfig()
105105
nzTargetOffset?: number = undefined;
106106

107107
@Input() nzContainer?: string | HTMLElement;

components/breadcrumb/breadcrumb.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
Renderer2,
1717
TemplateRef,
1818
ViewEncapsulation,
19-
booleanAttribute
19+
booleanAttribute,
20+
forwardRef
2021
} from '@angular/core';
2122
import { ActivatedRoute, NavigationEnd, PRIMARY_OUTLET, Params, Router } from '@angular/router';
2223
import { Subject } from 'rxjs';
@@ -39,7 +40,7 @@ export interface BreadcrumbOption {
3940
selector: 'nz-breadcrumb',
4041
exportAs: 'nzBreadcrumb',
4142
preserveWhitespaces: false,
42-
providers: [{ provide: NzBreadcrumb, useExisting: NzBreadCrumbComponent }],
43+
providers: [{ provide: NzBreadcrumb, useExisting: forwardRef(() => NzBreadCrumbComponent) }],
4344
standalone: true,
4445
imports: [NzBreadCrumbItemComponent],
4546
template: `

components/core/config/config.service.ts

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { CSP_NONCE, Injectable, inject } from '@angular/core';
77
import { Observable, Subject } from 'rxjs';
8-
import { filter, mapTo } from 'rxjs/operators';
8+
import { filter, map } from 'rxjs/operators';
99

1010
import { NzSafeAny } from 'ng-zorro-antd/core/types';
1111

@@ -47,7 +47,7 @@ export class NzConfigService {
4747
getConfigChangeEventForComponent(componentName: NzConfigKey): Observable<void> {
4848
return this.configUpdated$.pipe(
4949
filter(n => n === componentName),
50-
mapTo(undefined)
50+
map(() => undefined)
5151
);
5252
}
5353

@@ -60,51 +60,51 @@ export class NzConfigService {
6060
}
6161
}
6262

63-
/* eslint-disable no-invalid-this */
64-
6563
/**
66-
* This decorator is used to decorate properties. If a property is decorated, it would try to load default value from
67-
* config.
64+
* This decorator is used to decorate class field. If a class field is decorated and unassigned, it would try to load default value from `NZ_CONFIG`
65+
*
66+
* @note that the class must have `_nzModuleName`({@link NzConfigKey}) property.
67+
* @example
68+
* ```ts
69+
* class ExampleComponent {
70+
* private readonly _nzModuleName: NzConfigKey = 'button';
71+
* @WithConfig() size: string = 'default';
72+
* }
73+
* ```
6874
*/
69-
// eslint-disable-next-line
70-
export function WithConfig<T>() {
71-
return function ConfigDecorator(
72-
target: NzSafeAny,
73-
propName: NzSafeAny,
74-
originalDescriptor?: TypedPropertyDescriptor<T>
75-
): NzSafeAny {
76-
const privatePropName = `$$__zorroConfigDecorator__${propName}`;
77-
78-
Object.defineProperty(target, privatePropName, {
79-
configurable: true,
80-
writable: true,
81-
enumerable: false
82-
});
75+
export function WithConfig<This, Value>() {
76+
return function (_value: undefined, context: ClassFieldDecoratorContext<This, Value>) {
77+
context.addInitializer(function () {
78+
const nzConfigService = inject(NzConfigService);
79+
const originalValue = this[context.name as keyof This];
80+
81+
let value: Value;
82+
let assignedByUser = false;
83+
84+
Object.defineProperty(this, context.name, {
85+
get: () => {
86+
const configValue = nzConfigService.getConfigForComponent(
87+
this['_nzModuleName' as keyof This] as NzConfigKey
88+
)?.[context.name as keyof NzConfig[NzConfigKey]];
89+
90+
if (assignedByUser) {
91+
return value;
92+
}
93+
94+
if (isDefined(configValue)) {
95+
return configValue;
96+
}
8397

84-
return {
85-
get(): T | undefined {
86-
const originalValue = originalDescriptor?.get ? originalDescriptor.get.bind(this)() : this[privatePropName];
87-
const assignedByUser = (this.propertyAssignCounter?.[propName] || 0) > 1;
88-
const configValue = this.nzConfigService.getConfigForComponent(this._nzModuleName)?.[propName];
89-
if (assignedByUser && isDefined(originalValue)) {
9098
return originalValue;
91-
} else {
92-
return isDefined(configValue) ? configValue : originalValue;
93-
}
94-
},
95-
set(value?: T): void {
96-
// If the value is assigned, we consider the newly assigned value as 'assigned by user'.
97-
this.propertyAssignCounter = this.propertyAssignCounter || {};
98-
this.propertyAssignCounter[propName] = (this.propertyAssignCounter[propName] || 0) + 1;
99-
100-
if (originalDescriptor?.set) {
101-
originalDescriptor.set.bind(this)(value!);
102-
} else {
103-
this[privatePropName] = value;
104-
}
105-
},
106-
configurable: true,
107-
enumerable: true
108-
};
99+
},
100+
set: (newValue: Value) => {
101+
// if the newValue is undefined, we also consider it as not assigned by user
102+
assignedByUser = isDefined(newValue);
103+
value = newValue;
104+
},
105+
enumerable: true,
106+
configurable: true
107+
});
108+
});
109109
};
110110
}

components/dropdown/dropdown.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class NzDropDownDirective implements AfterViewInit, OnDestroy, OnChanges
6464
@Input() nzDropdownMenu: NzDropdownMenuComponent | null = null;
6565
@Input() nzTrigger: 'click' | 'hover' = 'hover';
6666
@Input() nzMatchWidthElement: ElementRef | null = null;
67-
@Input({ transform: booleanAttribute }) @WithConfig<boolean>() nzBackdrop = false;
67+
@Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;
6868
@Input({ transform: booleanAttribute }) nzClickHide = true;
6969
@Input({ transform: booleanAttribute }) nzDisabled = false;
7070
@Input({ transform: booleanAttribute }) nzVisible = false;

components/float-button/float-button-top.component.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import {
1212
Component,
1313
ElementRef,
1414
EventEmitter,
15-
Inject,
15+
inject,
1616
Input,
1717
NgZone,
18+
numberAttribute,
1819
OnChanges,
1920
OnDestroy,
2021
OnInit,
21-
Optional,
2222
Output,
2323
SimpleChanges,
2424
TemplateRef,
@@ -31,8 +31,6 @@ import { debounceTime, takeUntil } from 'rxjs/operators';
3131
import { fadeMotion } from 'ng-zorro-antd/core/animation';
3232
import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
3333
import { NzDestroyService, NzScrollService } from 'ng-zorro-antd/core/services';
34-
import { NumberInput, NzSafeAny } from 'ng-zorro-antd/core/types';
35-
import { InputNumber } from 'ng-zorro-antd/core/util';
3634
import { NzIconModule } from 'ng-zorro-antd/icon';
3735

3836
import { NzFloatButtonComponent } from './float-button.component';
@@ -75,11 +73,9 @@ const passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: t
7573
})
7674
export class NzFloatButtonTopComponent implements OnInit, OnDestroy, OnChanges {
7775
readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;
78-
static ngAcceptInputType_nzVisibilityHeight: NumberInput;
79-
static ngAcceptInputType_nzDuration: NumberInput;
8076

8177
private scrollListenerDestroy$ = new Subject<void>();
82-
private target: HTMLElement | null = null;
78+
private target?: HTMLElement | null = null;
8379

8480
visible: boolean = false;
8581
dir: Direction = 'ltr';
@@ -91,9 +87,9 @@ export class NzFloatButtonTopComponent implements OnInit, OnDestroy, OnChanges {
9187
@Input() nzDescription: TemplateRef<void> | null = null;
9288

9389
@Input() nzTemplate?: TemplateRef<void>;
94-
@Input() @WithConfig() @InputNumber() nzVisibilityHeight: number = 400;
90+
@Input({ transform: numberAttribute }) @WithConfig() nzVisibilityHeight: number = 400;
9591
@Input() nzTarget?: string | HTMLElement;
96-
@Input() @InputNumber() nzDuration: number = 450;
92+
@Input({ transform: numberAttribute }) nzDuration: number = 450;
9793
@Output() readonly nzOnClick: EventEmitter<boolean> = new EventEmitter();
9894

9995
@ViewChild('backTop', { static: false })
@@ -114,18 +110,18 @@ export class NzFloatButtonTopComponent implements OnInit, OnDestroy, OnChanges {
114110
}
115111
}
116112

113+
private doc = inject(DOCUMENT);
117114
private backTopClickSubscription = Subscription.EMPTY;
118115

119116
constructor(
120-
@Inject(DOCUMENT) private doc: NzSafeAny,
121117
public nzConfigService: NzConfigService,
122118
private scrollSrv: NzScrollService,
123119
private platform: Platform,
124120
private cd: ChangeDetectorRef,
125121
private zone: NgZone,
126122
private cdr: ChangeDetectorRef,
127123
private destroy$: NzDestroyService,
128-
@Optional() private directionality: Directionality
124+
private directionality: Directionality
129125
) {
130126
this.dir = this.directionality.value;
131127
}

components/graph/graph.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
ViewChildren,
2424
ViewEncapsulation,
2525
booleanAttribute,
26+
forwardRef,
2627
inject
2728
} from '@angular/core';
2829
import { Observable, ReplaySubject, Subject, Subscription, forkJoin } from 'rxjs';
@@ -72,7 +73,7 @@ export function isDataSource(value: NzSafeAny): value is NzGraphData {
7273
encapsulation: ViewEncapsulation.None,
7374
selector: 'nz-graph',
7475
exportAs: 'nzGraph',
75-
providers: [{ provide: NzGraph, useExisting: NzGraphComponent }],
76+
providers: [{ provide: NzGraph, useExisting: forwardRef(() => NzGraphComponent) }],
7677
template: `
7778
<ng-content></ng-content>
7879
<svg width="100%" height="100%">

components/image/image-preview.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Component,
1414
ElementRef,
1515
EventEmitter,
16-
Inject,
16+
inject,
1717
NgZone,
1818
OnInit,
1919
ViewChild,
@@ -230,6 +230,7 @@ export class NzImagePreviewComponent implements OnInit {
230230
@ViewChild('imgRef') imageRef!: ElementRef<HTMLImageElement>;
231231
@ViewChild('imagePreviewWrapper', { static: true }) imagePreviewWrapper!: ElementRef<HTMLElement>;
232232

233+
private document = inject(DOCUMENT);
233234
private zoom: number;
234235
private rotate: number;
235236
private scaleStep: number;
@@ -251,8 +252,7 @@ export class NzImagePreviewComponent implements OnInit {
251252
public nzConfigService: NzConfigService,
252253
public config: NzImagePreviewOptions,
253254
private destroy$: NzDestroyService,
254-
private sanitizer: DomSanitizer,
255-
@Inject(DOCUMENT) private document: Document
255+
private sanitizer: DomSanitizer
256256
) {
257257
this.zoom = this.config.nzZoom ?? this._defaultNzZoom;
258258
this.scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;

components/select/select.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
224224
@Input() nzId: string | null = null;
225225
@Input() nzSize: NzSelectSizeType = 'default';
226226
@Input() nzStatus: NzStatus = '';
227-
@Input() @WithConfig<number>() nzOptionHeightPx = 32;
227+
@Input() @WithConfig() nzOptionHeightPx = 32;
228228
@Input() nzOptionOverflowSize = 8;
229229
@Input() nzDropdownClassName: string[] | string | null = null;
230230
@Input() nzDropdownMatchSelectWidth = true;
@@ -236,7 +236,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
236236
@Input() nzDropdownRender: TemplateRef<NzSafeAny> | null = null;
237237
@Input() nzCustomTemplate: TemplateRef<{ $implicit: NzSelectItemInterface }> | null = null;
238238
@Input()
239-
@WithConfig<TemplateRef<NzSafeAny> | string | null>()
239+
@WithConfig()
240240
nzSuffixIcon: TemplateRef<NzSafeAny> | string | null = null;
241241
@Input() nzClearIcon: TemplateRef<NzSafeAny> | null = null;
242242
@Input() nzRemoveIcon: TemplateRef<NzSafeAny> | null = null;
@@ -248,7 +248,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
248248
@Input() nzFilterOption: NzFilterOptionType = defaultFilterOption;
249249
@Input() compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;
250250
@Input({ transform: booleanAttribute }) nzAllowClear = false;
251-
@Input({ transform: booleanAttribute }) @WithConfig<boolean>() nzBorderless = false;
251+
@Input({ transform: booleanAttribute }) @WithConfig() nzBorderless = false;
252252
@Input({ transform: booleanAttribute }) nzShowSearch = false;
253253
@Input({ transform: booleanAttribute }) nzLoading = false;
254254
@Input({ transform: booleanAttribute }) nzAutoFocus = false;
@@ -257,7 +257,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
257257
@Input({ transform: booleanAttribute }) nzDisabled = false;
258258
@Input({ transform: booleanAttribute }) nzOpen = false;
259259
@Input({ transform: booleanAttribute }) nzSelectOnTab = false;
260-
@Input({ transform: booleanAttribute }) @WithConfig<boolean>() nzBackdrop = false;
260+
@Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;
261261
@Input() nzOptions: NzSelectOptionInterface[] = [];
262262

263263
@Input({ transform: booleanAttribute })

components/table/src/addon/filter-trigger.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class NzFilterTriggerComponent implements OnInit {
6060
@Input() nzDropdownMenu!: NzDropdownMenuComponent;
6161
@Input() nzVisible = false;
6262

63-
@Input({ transform: booleanAttribute }) @WithConfig<boolean>() nzBackdrop = false;
63+
@Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;
6464

6565
@Output() readonly nzVisibleChange = new EventEmitter<boolean>();
6666

0 commit comments

Comments
 (0)