diff --git a/npm/ng-packs/packages/components/page/src/page.component.html b/npm/ng-packs/packages/components/page/src/page.component.html index 8cbaf2fdda..45e22c5e37 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.html +++ b/npm/ng-packs/packages/components/page/src/page.component.html @@ -3,10 +3,10 @@ @if (customTitle) { } @else { - @if (title) { + @if (title()) {

- {{ title }} + {{ title() }}

} @@ -25,9 +25,9 @@ @if (customToolbar) { } @else { - @if (toolbarVisible) { -
- + @if (toolbarVisible()) { +
+
} } diff --git a/npm/ng-packs/packages/components/page/src/page.component.ts b/npm/ng-packs/packages/components/page/src/page.component.ts index 3ee5b7c2db..4c9e35a2b7 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.ts +++ b/npm/ng-packs/packages/components/page/src/page.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, ViewEncapsulation, ContentChild, input } from '@angular/core'; +import { Component, ViewEncapsulation, ContentChild, input, effect, signal } from '@angular/core'; import { PageTitleContainerComponent, PageBreadcrumbContainerComponent, @@ -16,21 +16,13 @@ import { PagePartDirective } from './page-part.directive'; imports: [BreadcrumbComponent, PageToolbarComponent, PagePartDirective], }) export class PageComponent { - @Input() title?: string; - - toolbarVisible = false; - _toolbarData: any; - @Input() set toolbar(val: any) { - this._toolbarData = val; - this.toolbarVisible = true; - } - - get toolbarData() { - return this._toolbarData; - } - + readonly title = input(undefined); + readonly toolbarInput = input(undefined, { alias: 'toolbar' }); readonly breadcrumb = input(true); + protected readonly toolbarVisible = signal(false); + protected readonly toolbarData = signal(undefined); + pageParts = { title: PageParts.title, breadcrumb: PageParts.breadcrumb, @@ -42,10 +34,20 @@ export class PageComponent { customBreadcrumb?: PageBreadcrumbContainerComponent; @ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent; + constructor() { + effect(() => { + const toolbar = this.toolbarInput(); + if (toolbar !== undefined) { + this.toolbarData.set(toolbar); + this.toolbarVisible.set(true); + } + }); + } + get shouldRenderRow() { return !!( - this.title || - this.toolbarVisible || + this.title() || + this.toolbarVisible() || this.breadcrumb() || this.customTitle || this.customBreadcrumb || diff --git a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts b/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts index 6f313d513b..889143c9ed 100644 --- a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts +++ b/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, inject, Input, input } from '@angular/core'; +import { ChangeDetectorRef, Component, inject, input } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; // Not an abstract class on purpose. Do not change! @@ -11,16 +11,16 @@ export class AbstractNgModelComponent implements ControlValueAcc onChange?: (value: T) => void; onTouched?: () => void; - @Input() + // Note: disabled needs to remain as a regular property because setDisabledState assigns to it disabled?: boolean; - readonly readonly = input(undefined); + readonly readonly = input(undefined); readonly valueFn = input<(value: U, previousValue?: T) => T>(value => value as any as T); readonly valueLimitFn = input<(value: T, previousValue?: T) => any>(value => false); - @Input() + // Note: value needs getter/setter for ControlValueAccessor and two-way binding set value(value: T) { value = this.valueFn()(value as any as U, this._value); diff --git a/npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts index 398eaef9cc..65be9c348a 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Directive, ElementRef, Input, inject } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, inject, input, numberAttribute } from '@angular/core'; @Directive({ selector: '[autofocus]', @@ -6,18 +6,9 @@ import { AfterViewInit, Directive, ElementRef, Input, inject } from '@angular/co export class AutofocusDirective implements AfterViewInit { private elRef = inject(ElementRef); - private _delay = 0; - - @Input('autofocus') - set delay(val: number | string | undefined) { - this._delay = Number(val) || 0; - } - - get delay() { - return this._delay; - } + readonly delay = input(0, { alias: 'autofocus', transform: numberAttribute }); ngAfterViewInit(): void { - setTimeout(() => this.elRef.nativeElement.focus(), this.delay as number); + setTimeout(() => this.elRef.nativeElement.focus(), this.delay()); } } diff --git a/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts index a8d8addd6c..367f483b21 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts @@ -1,4 +1,4 @@ -import { Directive, ElementRef, Input, inject } from '@angular/core'; +import { Directive, ElementRef, effect, inject, input } from '@angular/core'; @Directive({ selector: '[abpShowPassword]', @@ -6,10 +6,15 @@ import { Directive, ElementRef, Input, inject } from '@angular/core'; export class ShowPasswordDirective { protected readonly elementRef = inject(ElementRef); - @Input() set abpShowPassword(visible: boolean) { - const element = this.elementRef.nativeElement as HTMLInputElement; - if (!element) return; + readonly abpShowPassword = input(false); - element.type = visible ? 'text' : 'password'; + constructor() { + effect(() => { + const visible = this.abpShowPassword(); + const element = this.elementRef.nativeElement as HTMLInputElement; + if (!element) return; + + element.type = visible ? 'text' : 'password'; + }); } } diff --git a/npm/ng-packs/packages/feature-management/src/lib/directives/free-text-input.directive.ts b/npm/ng-packs/packages/feature-management/src/lib/directives/free-text-input.directive.ts index 6b6556dcfa..259d2f76a1 100644 --- a/npm/ng-packs/packages/feature-management/src/lib/directives/free-text-input.directive.ts +++ b/npm/ng-packs/packages/feature-management/src/lib/directives/free-text-input.directive.ts @@ -1,4 +1,4 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { Directive, effect, inject, input, signal, ElementRef, Renderer2 } from '@angular/core'; // TODO: improve this type export interface FreeTextType { @@ -9,7 +9,7 @@ export interface FreeTextType { }; } -export const INPUT_TYPES = { +export const INPUT_TYPES: Record = { numeric: 'number', default: 'text', }; @@ -19,21 +19,23 @@ export const INPUT_TYPES = { exportAs: 'inputAbpFeatureManagementFreeText', }) export class FreeTextInputDirective { - _feature: FreeTextType; - // eslint-disable-next-line @angular-eslint/no-input-rename - @Input('abpFeatureManagementFreeText') set feature(val: FreeTextType) { - this._feature = val; - this.setInputType(); - } + private readonly elRef = inject(ElementRef); + private readonly renderer = inject(Renderer2); - get feature() { - return this._feature; - } + readonly feature = input(undefined, { alias: 'abpFeatureManagementFreeText' }); - @HostBinding('type') type: string; + constructor() { + effect(() => { + const feature = this.feature(); + if (feature) { + this.setInputType(feature); + } + }); + } - private setInputType() { - const validatorType = this.feature?.valueType?.validator?.name.toLowerCase(); - this.type = INPUT_TYPES[validatorType] ?? INPUT_TYPES.default; + private setInputType(feature: FreeTextType) { + const validatorType = feature?.valueType?.validator?.name?.toLowerCase(); + const type = INPUT_TYPES[validatorType] ?? INPUT_TYPES['default']; + this.renderer.setAttribute(this.elRef.nativeElement, 'type', type); } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html index 4b2dbf611d..4480e34c96 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html @@ -1,9 +1,9 @@ -@if (items.length) { +@if (items().length) {
@@ -33,14 +33,12 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core'; imports: [FormsModule, LocalizationPipe], }) export class FormCheckboxComponent extends AbstractNgModelComponent { - @Input() label?: string; + readonly label = input(undefined); readonly labelClass = input('form-check-label'); readonly checkboxId = input.required(); - readonly checkboxStyle = input<{ - [klass: string]: any; -} | null | undefined>(undefined); + readonly checkboxStyle = input<{ [klass: string]: any } | null | undefined>(undefined); readonly checkboxClass = input('form-check-input'); readonly checkboxReadonly = input(false); - @Output() checkboxBlur = new EventEmitter(); - @Output() checkboxFocus = new EventEmitter(); + readonly checkboxBlur = output(); + readonly checkboxFocus = output(); } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts index 46bc10fa53..9ea55fb144 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, forwardRef, Input, Output, input } from '@angular/core'; +import { Component, forwardRef, input, output } from '@angular/core'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core'; @@ -6,9 +6,9 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core'; selector: 'abp-form-input', template: `
- @if (label) { + @if (label()) { }
@@ -36,13 +36,11 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core'; export class FormInputComponent extends AbstractNgModelComponent { readonly inputId = input.required(); readonly inputReadonly = input(false); - @Input() label = ''; + readonly label = input(''); readonly labelClass = input('form-label'); readonly inputPlaceholder = input(''); - readonly inputStyle = input<{ - [klass: string]: any; -} | null | undefined>(undefined); + readonly inputStyle = input<{ [klass: string]: any } | null | undefined>(undefined); readonly inputClass = input('form-control'); - @Output() formBlur = new EventEmitter(); - @Output() formFocus = new EventEmitter(); + readonly formBlur = output(); + readonly formFocus = output(); } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index d4ed4de9dd..efe34b2e78 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -1,11 +1,11 @@ -import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, inject, input } from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit, inject, input, effect, signal } from '@angular/core'; import { combineLatest, Subscription, timer } from 'rxjs'; import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng.core'; @Component({ selector: 'abp-loader-bar', template: ` -
+
{ + const value = this.isLoadingInput(); + this.isLoading.set(value); + this.cdRef.detectChanges(); + }); + } + private readonly clearProgress = () => { this.progressLevel = 0; this.cdRef.detectChanges(); @@ -93,9 +88,9 @@ export class LoaderBarComponent implements OnDestroy, OnInit { } startLoading() { - if (this.isLoading || !this.interval.closed) return; + if (this.isLoading() || !this.interval.closed) return; - this.isLoading = true; + this.isLoading.set(true); this.progressLevel = 0; this.cdRef.detectChanges(); this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress); @@ -106,7 +101,7 @@ export class LoaderBarComponent implements OnDestroy, OnInit { this.interval.unsubscribe(); this.progressLevel = 100; - this.isLoading = false; + this.isLoading.set(false); if (!this.timer.closed) return; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/toast-container/toast-container.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/toast-container/toast-container.component.html index 0a70984b37..9969fd693f 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/toast-container/toast-container.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/toast-container/toast-container.component.html @@ -1,7 +1,7 @@
; @@ -18,18 +21,21 @@ export class ToastContainerComponent implements OnInit { toasts = [] as Toaster.Toast[]; - readonly top = input(undefined); - - @Input() - right = '30px'; - defaultRight = '30px'; - defaultMobileRight = '0'; - + readonly top = input(undefined); + readonly rightInput = input('30px', { alias: 'right' }); readonly bottom = input('30px'); + readonly left = input(undefined); + readonly toastKey = input(undefined); - readonly left = input(undefined); + protected readonly right = signal('30px'); + readonly defaultRight = '30px'; + readonly defaultMobileRight = '0'; - readonly toastKey = input(undefined); + constructor() { + effect(() => { + this.right.set(this.rightInput()); + }); + } ngOnInit() { this.setDefaultRight(); @@ -42,15 +48,14 @@ export class ToastContainerComponent implements OnInit { }); } - @HostListener('window:resize') onWindowResize() { this.setDefaultRight(); } setDefaultRight() { const screenWidth = window.innerWidth; - if (screenWidth < 768 && this.right == this.defaultRight) { - this.right = this.defaultMobileRight; + if (screenWidth < 768 && this.right() === this.defaultRight) { + this.right.set(this.defaultMobileRight); } }