-
+
@if (title()) {
{{ title() }}
}
diff --git a/libs/ui/src/lib/ui/note/note/note.component.ts b/libs/ui/src/lib/ui/note/note/note.component.ts
index 30d1a4e..0aec559 100644
--- a/libs/ui/src/lib/ui/note/note/note.component.ts
+++ b/libs/ui/src/lib/ui/note/note/note.component.ts
@@ -3,8 +3,9 @@ import {
Component,
Directive,
HostBinding,
- OnInit,
input,
+ computed,
+ inject,
} from '@angular/core';
import { NoteDataService } from '../infrastructure/note-data.service';
import { NoteStatus } from '../entities/note.model';
@@ -37,7 +38,7 @@ export class PiNoteActionContentDirective {}
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [MatIcon, PiTextSmallDirective, PiTextXSmallDirective],
})
-export class PiNoteComponent implements OnInit {
+export class PiNoteComponent {
@HostBinding('class') get classes(): string {
const alignmentValue = this.alignment();
const alignmentClass =
@@ -97,18 +98,16 @@ export class PiNoteComponent implements OnInit {
readonly appearance = input<'fill' | 'ghost'>('fill');
readonly type = input<'status' | 'simple'>('status');
- noteStatus?: NoteStatus;
+ private readonly noteDataService = inject(NoteDataService);
- constructor(private noteDataService: NoteDataService) {}
-
- ngOnInit(): void {
- this.noteStatus = this.getNoteStatus();
- }
-
- getNoteStatus(): NoteStatus | undefined {
+ /**
+ * Antes se calculaba en `ngOnInit`, así que no seguía a `status` si cambiaba
+ * después. Como `computed`, se recalcula solo.
+ */
+ readonly noteStatus = computed
(() => {
const noteStatusOptions = this.noteDataService.getNoteStatusData();
return noteStatusOptions.find(
(noteStatus) => this.status() === noteStatus.statusType,
);
- }
+ });
}
diff --git a/libs/ui/src/lib/ui/notification/infrastructure/notification.service.ts b/libs/ui/src/lib/ui/notification/infrastructure/notification.service.ts
index 3bbd35d..d127a50 100644
--- a/libs/ui/src/lib/ui/notification/infrastructure/notification.service.ts
+++ b/libs/ui/src/lib/ui/notification/infrastructure/notification.service.ts
@@ -1,4 +1,4 @@
-import { Injectable } from '@angular/core';
+import { Injectable, inject } from '@angular/core';
// Material
import { MatSnackBar } from '@angular/material/snack-bar';
@@ -10,7 +10,7 @@ import { PiSnackBarComponent } from '../snack-bar/snack-bar.component';
providedIn: 'root',
})
export class NotificationService {
- constructor(private _snackBar: MatSnackBar) {}
+ private readonly _snackBar = inject(MatSnackBar);
success(message: string, description?: string): void {
this._snackBar.openFromComponent(PiSnackBarComponent, {
diff --git a/libs/ui/src/lib/ui/notification/snack-bar/snack-bar.component.ts b/libs/ui/src/lib/ui/notification/snack-bar/snack-bar.component.ts
index 81ebedb..da6e7a7 100644
--- a/libs/ui/src/lib/ui/notification/snack-bar/snack-bar.component.ts
+++ b/libs/ui/src/lib/ui/notification/snack-bar/snack-bar.component.ts
@@ -2,10 +2,9 @@ import {
ChangeDetectionStrategy,
Component,
HostBinding,
- Inject,
- Optional,
forwardRef,
signal,
+ inject,
} from '@angular/core';
import {
MatSnackBarRef,
@@ -73,7 +72,10 @@ export class PiSnackBarComponent {
/** The instance of the component making up the content of the snack bar. */
private readonly snackBarRef!: MatSnackBarRef;
- constructor(@Optional() @Inject(MAT_SNACK_BAR_DATA) public data: any) {
+ readonly data = inject(MAT_SNACK_BAR_DATA, { optional: true });
+
+ constructor() {
+ const data = this.data;
if (data) {
this.message.set(data.message);
this.icon.set(data.icon);
diff --git a/libs/ui/src/lib/ui/paginator/paginator/paginator.component.ts b/libs/ui/src/lib/ui/paginator/paginator/paginator.component.ts
index 2d04b75..a56fad5 100644
--- a/libs/ui/src/lib/ui/paginator/paginator/paginator.component.ts
+++ b/libs/ui/src/lib/ui/paginator/paginator/paginator.component.ts
@@ -1,12 +1,13 @@
import {
ChangeDetectionStrategy,
Component,
- OnInit,
HostBinding,
forwardRef,
input,
model,
output,
+ effect,
+ untracked,
} from '@angular/core';
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
@@ -23,7 +24,7 @@ import { PiIconComponent } from '../../icon/icon/icon.component';
forwardRef(() => PiPaginatorComponent),
],
})
-export class PiPaginatorComponent implements OnInit {
+export class PiPaginatorComponent {
@HostBinding('class') className = 'pi-paginator';
readonly currentPage = model(1);
readonly pageSize = input.required();
@@ -36,8 +37,13 @@ export class PiPaginatorComponent implements OnInit {
firstPagesRange = 0;
- ngOnInit(): void {
- this.initFirstPages();
+ constructor() {
+ // `initFirstPages` lee el input `totalPages`, que no está disponible en el
+ // constructor; con un efecto además se recalcula si cambia.
+ effect(() => {
+ this.totalPages();
+ untracked(() => this.initFirstPages());
+ });
}
get pages() {
diff --git a/libs/ui/src/lib/ui/panel/base-panel.component.ts b/libs/ui/src/lib/ui/panel/base-panel.component.ts
index 35b72e6..4ec305c 100644
--- a/libs/ui/src/lib/ui/panel/base-panel.component.ts
+++ b/libs/ui/src/lib/ui/panel/base-panel.component.ts
@@ -1,5 +1,5 @@
// Angular
-import { Directive, OnInit, input } from '@angular/core';
+import { Directive, input } from '@angular/core';
import {
alignment,
borderRadius,
@@ -13,7 +13,7 @@ import {
import { status } from '../../util/status';
@Directive()
-export abstract class PiBasePanelComponent implements OnInit {
+export abstract class PiBasePanelComponent {
readonly alignment = input('center');
readonly borderRadius = input('large');
readonly color = input('white');
@@ -38,22 +38,6 @@ export abstract class PiBasePanelComponent implements OnInit {
readonly status = input.required();
- ngOnInit(): void {
- this.alignmentClass;
- this.borderRadiusClass;
- this.colorClass;
- this.flexDirectionClass;
- this.justifyClass;
- this.widthClass;
- this.outlineClass;
- this.paddingClass;
- this.gapClass;
- this.statusClass;
- this.isStrokedClass;
- this.modeClass;
- this.opacityClass;
- }
-
protected get widthClass(): string | undefined {
const width = this.width();
return width && `pi-panel__width--${width}`;
diff --git a/libs/ui/src/lib/ui/panel/expansion-panel/expansion-panel.component.ts b/libs/ui/src/lib/ui/panel/expansion-panel/expansion-panel.component.ts
index 0943f8e..3a199ef 100644
--- a/libs/ui/src/lib/ui/panel/expansion-panel/expansion-panel.component.ts
+++ b/libs/ui/src/lib/ui/panel/expansion-panel/expansion-panel.component.ts
@@ -2,14 +2,13 @@ import {
ChangeDetectionStrategy,
Component,
HostBinding,
- OnChanges,
- OnInit,
- SimpleChanges,
TemplateRef,
input,
model,
output,
contentChild,
+ effect,
+ untracked,
} from '@angular/core';
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
import { ComponentFamilyClass } from '../../../styles';
@@ -50,10 +49,7 @@ import { TranslatePipe } from '@ngx-translate/core';
TranslatePipe,
],
})
-export class PiExpansionPanelComponent
- extends PiBasePanelComponent
- implements OnInit, OnChanges
-{
+export class PiExpansionPanelComponent extends PiBasePanelComponent {
@HostBinding('class') get classes(): string {
const type = this.type();
const typeClass = type && `pi-panel__expansion--type-${type}`;
@@ -90,12 +86,16 @@ export class PiExpansionPanelComponent
readonly expandableContentRef =
contentChild>('expandableContent');
- override ngOnInit(): void {
- if (this.status() === 'disabled') this.isCollapsed.set(true);
- }
-
- ngOnChanges({ status }: SimpleChanges): void {
- if (status?.currentValue === 'disabled') this.isCollapsed.set(true);
+ constructor() {
+ super();
+ // Antes eran un `ngOnInit` y un `ngOnChanges` que hacían lo mismo (uno para
+ // el valor inicial y otro para los cambios). Con `status` siendo un input
+ // de señal, un solo efecto cubre ambos casos.
+ effect(() => {
+ if (this.status() === 'disabled') {
+ untracked(() => this.isCollapsed.set(true));
+ }
+ });
}
toggle(): void {
diff --git a/libs/ui/src/lib/ui/panel/panel.directive.ts b/libs/ui/src/lib/ui/panel/panel.directive.ts
index e61aab1..aaf684a 100644
--- a/libs/ui/src/lib/ui/panel/panel.directive.ts
+++ b/libs/ui/src/lib/ui/panel/panel.directive.ts
@@ -1,18 +1,14 @@
-import { Directive, HostBinding, OnInit, input } from '@angular/core';
+import { Directive, HostBinding, input } from '@angular/core';
import { padding } from '../../styles';
@Directive()
-export abstract class PiBasePanelContentDirective implements OnInit {
+export abstract class PiBasePanelContentDirective {
@HostBinding('class') get commonClasses(): string {
return ['pi-panel-content', this.innerPaddingClass].join(' ');
}
readonly innerPadding = input();
- ngOnInit(): void {
- this.innerPaddingClass;
- }
-
protected get innerPaddingClass(): string {
const innerPadding = this.innerPadding();
return innerPadding
diff --git a/libs/ui/src/lib/ui/select/base-select.component.ts b/libs/ui/src/lib/ui/select/base-select.component.ts
index 88976d9..0419e42 100644
--- a/libs/ui/src/lib/ui/select/base-select.component.ts
+++ b/libs/ui/src/lib/ui/select/base-select.component.ts
@@ -11,6 +11,7 @@ import {
contentChildren,
viewChildren,
ChangeDetectionStrategy,
+ inject,
} from '@angular/core';
import { FormValueControl, ValidationError } from '@angular/forms/signals';
import { PiSelectOptionComponent } from './select-option/select-option.component';
@@ -197,10 +198,8 @@ export abstract class PiBaseSelectComponent<
read: ElementRef,
});
- constructor(
- protected el: ElementRef,
- protected readonly _renderer: Renderer2,
- ) {}
+ protected readonly el = inject(ElementRef);
+ protected readonly _renderer = inject(Renderer2);
trackByFn(index: number): number | undefined {
return index;
diff --git a/libs/ui/src/lib/ui/select/select-carousel/select-carousel.component.ts b/libs/ui/src/lib/ui/select/select-carousel/select-carousel.component.ts
index 72fd71c..2a0bc88 100644
--- a/libs/ui/src/lib/ui/select/select-carousel/select-carousel.component.ts
+++ b/libs/ui/src/lib/ui/select/select-carousel/select-carousel.component.ts
@@ -5,9 +5,9 @@ import {
Component,
ElementRef,
HostBinding,
- Renderer2,
effect,
input,
+ inject,
} from '@angular/core';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import _ from 'lodash';
@@ -78,13 +78,11 @@ export class PiSelectCarouselComponent
* @param el - Element reference of the component.
* @param _renderer - Renderer to modify native elements.
*/
- constructor(
- private readonly translateService: TranslateService,
- protected override el: ElementRef,
- protected override readonly _renderer: Renderer2,
- private _cdr: ChangeDetectorRef,
- ) {
- super(el, _renderer);
+ private readonly translateService = inject(TranslateService);
+ private readonly _cdr = inject(ChangeDetectorRef);
+
+ constructor() {
+ super();
effect(() => {
this.childrenOptionsComponents();
diff --git a/libs/ui/src/lib/ui/select/select-multiple/select-multiple.component.ts b/libs/ui/src/lib/ui/select/select-multiple/select-multiple.component.ts
index f9f1317..dd0aef7 100644
--- a/libs/ui/src/lib/ui/select/select-multiple/select-multiple.component.ts
+++ b/libs/ui/src/lib/ui/select/select-multiple/select-multiple.component.ts
@@ -5,9 +5,9 @@ import {
Component,
ElementRef,
HostBinding,
- Renderer2,
effect,
input,
+ inject,
} from '@angular/core';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import { PiBaseSelectComponent } from '../base-select.component';
@@ -88,13 +88,11 @@ export class PiSelectMultipleComponent
*/
readonly selectAllLabel = input();
- constructor(
- private readonly translateService: TranslateService,
- protected override el: ElementRef,
- protected override readonly _renderer: Renderer2,
- private _cdr: ChangeDetectorRef,
- ) {
- super(el, _renderer);
+ private readonly translateService = inject(TranslateService);
+ private readonly _cdr = inject(ChangeDetectorRef);
+
+ constructor() {
+ super();
/**
* Sustituye al `merge(...).subscribe(...)` sobre `control.valueChanges` +
diff --git a/libs/ui/src/lib/ui/select/select-period/select-period.component.ts b/libs/ui/src/lib/ui/select/select-period/select-period.component.ts
index a068429..6e27bc1 100644
--- a/libs/ui/src/lib/ui/select/select-period/select-period.component.ts
+++ b/libs/ui/src/lib/ui/select/select-period/select-period.component.ts
@@ -6,8 +6,8 @@ import {
ElementRef,
HostBinding,
HostListener,
- Renderer2,
effect,
+ inject,
} from '@angular/core';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import { PiBaseSelectComponent } from '../base-select.component';
@@ -84,13 +84,11 @@ export class PiSelectPeriodComponent
* @param el - Element reference of the component.
* @param _renderer - Renderer to modify native elements.
*/
- constructor(
- private readonly translateService: TranslateService,
- protected override el: ElementRef,
- protected override readonly _renderer: Renderer2,
- private _cdr: ChangeDetectorRef,
- ) {
- super(el, _renderer);
+ private readonly translateService = inject(TranslateService);
+ private readonly _cdr = inject(ChangeDetectorRef);
+
+ constructor() {
+ super();
effect(() => {
this.childrenOptionsComponents();
diff --git a/libs/ui/src/lib/ui/select/select/select.component.ts b/libs/ui/src/lib/ui/select/select/select.component.ts
index 878e2c3..72495ba 100644
--- a/libs/ui/src/lib/ui/select/select/select.component.ts
+++ b/libs/ui/src/lib/ui/select/select/select.component.ts
@@ -6,10 +6,10 @@ import {
ElementRef,
HostBinding,
HostListener,
- Renderer2,
effect,
forwardRef,
input,
+ inject,
} from '@angular/core';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import { PiBaseSelectComponent } from '../base-select.component';
@@ -92,13 +92,11 @@ export class PiSelectComponent
* @param el - Element reference of the component.
* @param _renderer - Renderer to modify native elements.
*/
- constructor(
- private readonly translateService: TranslateService,
- protected override el: ElementRef,
- protected override readonly _renderer: Renderer2,
- private _cdr: ChangeDetectorRef,
- ) {
- super(el, _renderer);
+ private readonly translateService = inject(TranslateService);
+ private readonly _cdr = inject(ChangeDetectorRef);
+
+ constructor() {
+ super();
/**
* Sustituye al `merge(...).subscribe(...)` sobre `control.valueChanges` +
diff --git a/libs/ui/src/lib/ui/tab/tab.directive.ts b/libs/ui/src/lib/ui/tab/tab.directive.ts
index 9d9855b..39a3131 100644
--- a/libs/ui/src/lib/ui/tab/tab.directive.ts
+++ b/libs/ui/src/lib/ui/tab/tab.directive.ts
@@ -1,11 +1,11 @@
-import { Directive, TemplateRef } from '@angular/core';
+import { Directive, TemplateRef, inject } from '@angular/core';
@Directive({ selector: '[pi-tab-content]' })
export class PiTabContentDirective {
- constructor(public templateRef: TemplateRef) {}
+ public readonly templateRef = inject(TemplateRef);
}
@Directive({ selector: '[pi-tab-element]' })
export class PiTabElementDirective {
- constructor(public templateRef: TemplateRef) {}
+ readonly templateRef = inject>(TemplateRef);
}
diff --git a/libs/ui/src/lib/ui/text/base-text-viewer.component.ts b/libs/ui/src/lib/ui/text/base-text-viewer.component.ts
index fc9a086..fb9811f 100644
--- a/libs/ui/src/lib/ui/text/base-text-viewer.component.ts
+++ b/libs/ui/src/lib/ui/text/base-text-viewer.component.ts
@@ -1,5 +1,5 @@
// Angular
-import { Directive, HostBinding, OnInit, input } from '@angular/core';
+import { Directive, HostBinding, input } from '@angular/core';
// Style definitions
import {
@@ -17,7 +17,7 @@ import {
} from '../../styles';
@Directive()
-export abstract class PiBaseTextViewerComponent implements OnInit {
+export abstract class PiBaseTextViewerComponent {
@HostBinding('class') get classes(): string {
return [
ComponentFamilyClass.Text,
@@ -58,23 +58,6 @@ export abstract class PiBaseTextViewerComponent implements OnInit {
readonly label = input();
readonly value = input();
- ngOnInit(): void {
- this.alignmentClass;
- this.borderTypeClass;
- this.colorClass;
- this.flexDirectionClass;
- this.fontSizeClass;
- this.fontStyleClass;
- this.fontWeightClass;
- this.justifyClass;
- this.iconSizeClass;
- this.iconColorClass;
- this.isDisabledClass;
- this.hasLabelClass;
- this.hasValueClass;
- this.iconAppearanceClass;
- }
-
protected get alignmentClass(): string {
const alignmentValue = this.alignment();
return alignmentValue && `pi-text-viewer__align--${alignmentValue}`;
diff --git a/libs/ui/src/lib/ui/tooltip/tooltip.directive.ts b/libs/ui/src/lib/ui/tooltip/tooltip.directive.ts
index 79878b7..beaef7e 100644
--- a/libs/ui/src/lib/ui/tooltip/tooltip.directive.ts
+++ b/libs/ui/src/lib/ui/tooltip/tooltip.directive.ts
@@ -3,9 +3,10 @@ import {
ElementRef,
HostBinding,
OnDestroy,
- OnInit,
Renderer2,
input,
+ effect,
+ inject,
} from '@angular/core';
import { MatTooltip, TooltipPosition } from '@angular/material/tooltip';
@@ -13,7 +14,7 @@ import { MatTooltip, TooltipPosition } from '@angular/material/tooltip';
selector: '[pi-tooltip]',
providers: [MatTooltip],
})
-export class PiTooltipDirective implements OnInit, OnDestroy {
+export class PiTooltipDirective implements OnDestroy {
@HostBinding('class') className = 'pi-tooltip-dispatcher';
readonly tooltipText = input();
@@ -25,19 +26,24 @@ export class PiTooltipDirective implements OnInit, OnDestroy {
private mouseoutListener!: () => void;
private clickListener!: () => void;
- constructor(
- private tooltip: MatTooltip,
- private el: ElementRef,
- private renderer: Renderer2,
- ) {}
+ private readonly tooltip = inject(MatTooltip);
+ private readonly el = inject(ElementRef);
+ private readonly renderer = inject(Renderer2);
- ngOnInit(): void {
- this.tooltip.tooltipClass = [
- 'pi-tooltip',
- this.typeClass,
- this.colorClass,
- ].join(' ');
+ constructor() {
+ // La clase depende de inputs, así que va en un efecto; los listeners no
+ // dependen de nada y se registran una sola vez.
+ effect(() => {
+ this.tooltip.tooltipClass = [
+ 'pi-tooltip',
+ this.typeClass,
+ this.colorClass,
+ ].join(' ');
+ });
+ this.registerListeners();
+ }
+ private registerListeners(): void {
this.mouseoverListener = this.renderer.listen(
this.el.nativeElement,
'mouseover',
diff --git a/libs/ui/src/lib/ui/wrapper/base.wrapper.ts b/libs/ui/src/lib/ui/wrapper/base.wrapper.ts
index a64f28d..6c37f4a 100644
--- a/libs/ui/src/lib/ui/wrapper/base.wrapper.ts
+++ b/libs/ui/src/lib/ui/wrapper/base.wrapper.ts
@@ -1,5 +1,5 @@
// Angular
-import { Directive, OnInit, input } from '@angular/core';
+import { Directive, input } from '@angular/core';
import { itemsWidth } from '../../styles';
import {
@@ -12,7 +12,7 @@ import {
} from '../../styles';
@Directive()
-export abstract class PiBaseWrapper implements OnInit {
+export abstract class PiBaseWrapper {
readonly alignment = input('center');
readonly flexDirection = input('row');
readonly gap = input.required();
@@ -23,17 +23,6 @@ export abstract class PiBaseWrapper implements OnInit {
readonly maxWidth = input('edge-to-edge');
readonly itemsWidth = input();
- ngOnInit(): void {
- this.alignmentClass;
- this.flexDirectionClass;
- this.gridClass;
- this.hasBackgroundClass;
- this.hasPaddingClass;
- this.justifyClass;
- this.itemsWidthClass;
- this.maxWidthClass;
- }
-
protected get maxWidthClass(): string | undefined {
const maxWidthValue = this.maxWidth();
return maxWidthValue && `pi-wrapper__${maxWidthValue}`;
diff --git a/libs/ui/src/lib/util/affix/affix.directive.ts b/libs/ui/src/lib/util/affix/affix.directive.ts
index 04067af..fde4ce3 100644
--- a/libs/ui/src/lib/util/affix/affix.directive.ts
+++ b/libs/ui/src/lib/util/affix/affix.directive.ts
@@ -2,14 +2,15 @@ import {
Directive,
ElementRef,
HostBinding,
- OnInit,
Renderer2,
input,
+ afterNextRender,
+ inject,
} from '@angular/core';
import { unit } from '../models';
@Directive()
-export abstract class PiBaseAffixDirective implements OnInit {
+export abstract class PiBaseAffixDirective {
@HostBinding('class') get classes(): string {
return ['pi-affix', `pi-affix__appearance--${this.appearance()}`].join(' ');
}
@@ -17,12 +18,17 @@ export abstract class PiBaseAffixDirective implements OnInit {
readonly unit = input();
readonly appearance = input<'ghost' | 'fill'>('ghost');
- constructor(
- private renderer: Renderer2,
- private el: ElementRef,
- ) {}
+ private readonly renderer = inject(Renderer2);
+ private readonly el = inject(ElementRef);
- ngOnInit() {
+ constructor() {
+ // Pinta DOM a partir de un input, así que no puede ir en el cuerpo del
+ // constructor (los inputs aún no tienen valor). `afterNextRender` corre una
+ // sola vez tras el primer render, que es lo que hacía el `ngOnInit`.
+ afterNextRender(() => this.renderUnit());
+ }
+
+ private renderUnit(): void {
const unitValue = this.unit();
if (unitValue) {
const span = this.renderer.createElement('span');
diff --git a/libs/ui/src/lib/util/amplitude/amplitude.service.ts b/libs/ui/src/lib/util/amplitude/amplitude.service.ts
index 5c6385f..ece5f4b 100644
--- a/libs/ui/src/lib/util/amplitude/amplitude.service.ts
+++ b/libs/ui/src/lib/util/amplitude/amplitude.service.ts
@@ -1,5 +1,5 @@
import { isPlatformBrowser } from '@angular/common';
-import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
+import { Inject, Injectable, PLATFORM_ID, inject } from '@angular/core';
@Injectable({
providedIn: 'root',
@@ -8,7 +8,9 @@ export class AmplitudeService {
private amp: any;
private ampEnabled = false;
- constructor(@Inject(PLATFORM_ID) public platformId: object) {
+ readonly platformId = inject