fix: adapta escrituras internas a model() y signal queries (toObservable)
This commit is contained in:
@@ -1,56 +1,60 @@
|
||||
import {
|
||||
AfterContentInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
HostBinding,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
input,
|
||||
output,
|
||||
contentChildren
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
HostBinding,
|
||||
input,
|
||||
model,
|
||||
contentChildren
|
||||
} from '@angular/core';
|
||||
import { padding, styleType, textColor } from '../../../styles';
|
||||
import { PiAccordionItemDirective } from '../directives/accordion-content.directive';
|
||||
import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
|
||||
import { PiDynamicColorDirective } from '../../../util/color/directives/colors.directive';
|
||||
import { PiTextViewerComponent } from '../../text/text-viewer/text-viewer.component';
|
||||
import { PiChipStatusComponent } from '../../chip/chip-status/chip-status.component';
|
||||
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
|
||||
import { PiIconComponent } from '../../icon/icon/icon.component';
|
||||
import { PiAccordionItemDirective } from '../directives/accordion-content.directive';
|
||||
import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
|
||||
import { PiDynamicColorDirective } from '../../../util/color/directives/colors.directive';
|
||||
import { PiTextViewerComponent } from '../../text/text-viewer/text-viewer.component';
|
||||
import { PiChipStatusComponent } from '../../chip/chip-status/chip-status.component';
|
||||
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
|
||||
import { PiIconComponent } from '../../icon/icon/icon.component';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'pi-accordion',
|
||||
templateUrl: './accordion.component.html',
|
||||
styleUrls: ['../styles/accordion.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
NgIf,
|
||||
NgFor,
|
||||
PiDynamicColorDirective,
|
||||
PiTextViewerComponent,
|
||||
NgTemplateOutlet,
|
||||
PiChipStatusComponent,
|
||||
PiIconButtonComponent,
|
||||
PiIconComponent,
|
||||
TranslatePipe,
|
||||
],
|
||||
@Component({
|
||||
selector: 'pi-accordion',
|
||||
templateUrl: './accordion.component.html',
|
||||
styleUrls: ['../styles/accordion.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
NgIf,
|
||||
NgFor,
|
||||
PiDynamicColorDirective,
|
||||
PiTextViewerComponent,
|
||||
NgTemplateOutlet,
|
||||
PiChipStatusComponent,
|
||||
PiIconButtonComponent,
|
||||
PiIconComponent,
|
||||
TranslatePipe,
|
||||
],
|
||||
})
|
||||
export class PiAccordionComponent implements OnChanges, AfterContentInit {
|
||||
export class PiAccordionComponent {
|
||||
@HostBinding('class') get classes(): string {
|
||||
const colorClass = `pi-accordion__${this.color()}`;
|
||||
const appearance = this.appearance();
|
||||
const appearance = this.appearance();
|
||||
const appearanceClass =
|
||||
appearance !== 'default' && `pi-accordion__appearance--${appearance}`;
|
||||
const direction = this.direction();
|
||||
const direction = this.direction();
|
||||
const directionClass =
|
||||
direction !== 'default' && `pi-accordion__direction--${direction}`;
|
||||
const paddingClass = `pi-accordion__padding--${this.padding()}`;
|
||||
return ['pi-accordion', colorClass, appearanceClass, directionClass, paddingClass].join(' ');
|
||||
}
|
||||
|
||||
readonly expandedItemIndex = input.required<number>();
|
||||
/**
|
||||
* `model` en vez de `input` + output manual: el componente escribe este valor
|
||||
* al plegar/desplegar. El evento `expandedItemIndexChange` que antes se
|
||||
* declaraba a mano lo genera `model()` automáticamente.
|
||||
*
|
||||
* El tipo incluye `null` porque `toggleState` lo asigna al colapsar; antes
|
||||
* estaba declarado como `number` y esa asignación no compilaba.
|
||||
*/
|
||||
readonly expandedItemIndex = model<number | null>(null);
|
||||
readonly appearance = input<'default' | 'outline' | 'fill'>('default');
|
||||
readonly color = input<styleType>('white');
|
||||
readonly direction = input<'default' | 'horizontal'>('default');
|
||||
@@ -59,44 +63,22 @@ export class PiAccordionComponent implements OnChanges, AfterContentInit {
|
||||
|
||||
readonly hasChevron = input(true);
|
||||
|
||||
readonly expandedItemIndexChange = output<number>();
|
||||
|
||||
readonly items = contentChildren(PiAccordionItemDirective);
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (
|
||||
changes['expandedItemIndex'] &&
|
||||
changes['expandedItemIndex'].currentValue !== changes['expandedItemIndex'].previousValue
|
||||
) {
|
||||
this.expandedItemIndex = changes['expandedItemIndex'].currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this.items().changes.subscribe(() => {
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
}
|
||||
// `items` es una signal query: Angular reevalúa la plantilla cuando cambia,
|
||||
// así que el ngAfterContentInit que sólo hacía markForCheck() sobra.
|
||||
|
||||
toggleState = (item: PiAccordionItemDirective, index: number) => {
|
||||
if (this.direction() === 'horizontal' && this.isItemExpanded(index)) return;
|
||||
if (item.status() === 'disabled') return;
|
||||
const expandedItemIndex = this.expandedItemIndex();
|
||||
if (expandedItemIndex === index) {
|
||||
this.expandedItemIndex = null;
|
||||
} else {
|
||||
this.expandedItemIndex = index;
|
||||
}
|
||||
this.expandedItemIndexChange.emit(expandedItemIndex);
|
||||
this.expandedItemIndex.set(this.expandedItemIndex() === index ? null : index);
|
||||
};
|
||||
|
||||
isItemExpanded = (index: number) => this.expandedItemIndex() === index;
|
||||
|
||||
setAccordionItemClasses(item: PiAccordionItemDirective, index: number): string {
|
||||
const expandedClass = this.isItemExpanded(index) ? 'is-expanded' : 'is-collapsed';
|
||||
const status = item.status();
|
||||
const status = item.status();
|
||||
const statusClass = status && 'has-status' + ' ' + `is-${status}`;
|
||||
const isConfidentialClass = item.isConfidential() ? 'is-confidential' : '';
|
||||
return [expandedClass, statusClass, isConfidentialClass].join(' ');
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
Component,
|
||||
HostBinding,
|
||||
input,
|
||||
model,
|
||||
output
|
||||
} from '@angular/core';
|
||||
import { ComponentFamilyClass } from '../../../styles';
|
||||
@@ -29,7 +30,7 @@ export class PiSwitchButtonComponent extends PiBaseButtonComponent {
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
readonly isActive = input(true);
|
||||
readonly isActive = model(true);
|
||||
readonly toggledTo = output();
|
||||
|
||||
readonly contentType = input<'icon' | 'text'>('icon');
|
||||
@@ -40,10 +41,10 @@ export class PiSwitchButtonComponent extends PiBaseButtonComponent {
|
||||
|
||||
toggleSelected(): void {
|
||||
if (this.isActive()) {
|
||||
this.isActive = false;
|
||||
this.isActive.set(false);
|
||||
this.toggledTo.emit('off');
|
||||
} else {
|
||||
this.isActive = true;
|
||||
this.isActive.set(true);
|
||||
this.toggledTo.emit('on');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// Angular
|
||||
import {
|
||||
AfterViewChecked,
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Renderer2,
|
||||
SimpleChanges,
|
||||
input,
|
||||
output,
|
||||
viewChild,
|
||||
contentChildren
|
||||
import {
|
||||
AfterViewChecked,
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Renderer2,
|
||||
SimpleChanges,
|
||||
input,
|
||||
output,
|
||||
viewChild,
|
||||
contentChildren
|
||||
} from '@angular/core';
|
||||
|
||||
// Shared
|
||||
import { ComponentFamilyClass, justify, theming } from '../../../styles';
|
||||
import { Device, DeviceConfigsFacade } from '../../../util/device-configs';
|
||||
import { PiCarouselItemDirective } from '../carousel.directive';
|
||||
import { Subject, combineLatest, skip, takeUntil } from 'rxjs';
|
||||
import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
|
||||
import { Subject, combineLatest, skip, takeUntil } from 'rxjs';
|
||||
import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
|
||||
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
|
||||
|
||||
@Component({
|
||||
selector: 'pi-carousel',
|
||||
templateUrl: './carousel.component.html',
|
||||
styleUrls: ['./carousel.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
NgIf,
|
||||
PiIconButtonComponent,
|
||||
NgFor,
|
||||
NgTemplateOutlet,
|
||||
],
|
||||
@Component({
|
||||
selector: 'pi-carousel',
|
||||
templateUrl: './carousel.component.html',
|
||||
styleUrls: ['./carousel.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
NgIf,
|
||||
PiIconButtonComponent,
|
||||
NgFor,
|
||||
NgTemplateOutlet,
|
||||
],
|
||||
})
|
||||
export class PiCarouselComponent
|
||||
implements OnInit, OnChanges, AfterViewInit, AfterViewChecked, OnDestroy
|
||||
{
|
||||
@HostBinding('class') get classes(): string {
|
||||
const carouselItems = this.carouselItems();
|
||||
const carouselItems = this.carouselItems();
|
||||
const itemsNumberClass =
|
||||
carouselItems && `pi-carousel__${carouselItems.length}-items`;
|
||||
const direction = this.direction();
|
||||
const direction = this.direction();
|
||||
const directionTypeClass = direction && `pi-carousel__${direction}`;
|
||||
const colorClass = `pi-carousel__${this.color()}`;
|
||||
const typeClass = `pi-carousel__${this.type()}`;
|
||||
const isDraggableClass = this.isDraggable() ? 'is-draggable' : '';
|
||||
const justifyValue = this.justify();
|
||||
const justifyValue = this.justify();
|
||||
const justifyClass = justifyValue && `pi-carousel__justify-content--${justifyValue}`;
|
||||
return [
|
||||
ComponentFamilyClass.Carousel,
|
||||
@@ -256,10 +256,8 @@ export class PiCarouselComponent
|
||||
if (this.isDraggable()) {
|
||||
this.setDragEventListeners();
|
||||
}
|
||||
|
||||
this.carouselItems().changes.pipe(takeUntil(this.destroyed$)).subscribe(() => {
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
// La suscripción a `carouselItems.changes` sólo hacía markForCheck();
|
||||
// al ser `carouselItems` una signal query, Angular ya lo hace solo.
|
||||
}
|
||||
|
||||
ngAfterViewChecked(): void {
|
||||
@@ -305,13 +303,13 @@ export class PiCarouselComponent
|
||||
}
|
||||
|
||||
setItemsPerPage(): void {
|
||||
const itemWidth = this.itemWidth();
|
||||
const itemWidth = this.itemWidth();
|
||||
if (!!itemWidth) {
|
||||
this.itemsPerPage = Math.floor(this.carouselContentElement.clientWidth / itemWidth) || 1;
|
||||
} else {
|
||||
const itemsDesktop = this.itemsDesktop();
|
||||
const itemsTablet = this.itemsTablet();
|
||||
const itemsMobile = this.itemsMobile();
|
||||
const itemsDesktop = this.itemsDesktop();
|
||||
const itemsTablet = this.itemsTablet();
|
||||
const itemsMobile = this.itemsMobile();
|
||||
switch (this.device()) {
|
||||
case 'DESKTOP':
|
||||
this.itemsPerPage = itemsDesktop ? itemsDesktop : this.carouselItems().length;
|
||||
@@ -436,7 +434,7 @@ export class PiCarouselComponent
|
||||
* Sets a minimum dragging width based on either 80% of the item width if provided
|
||||
* Otherwise 80% of the width of one item in terms of the number of items displayed per page
|
||||
*/
|
||||
const itemWidth = this.itemWidth();
|
||||
const itemWidth = this.itemWidth();
|
||||
const minDraggingWidth = itemWidth ? 0.8 * itemWidth : 0.8 * (100 / this.itemsPerPage);
|
||||
|
||||
this.isDragging = true;
|
||||
@@ -470,7 +468,7 @@ export class PiCarouselComponent
|
||||
}
|
||||
|
||||
private carouselTranslation(currentItem: number): void {
|
||||
const type = this.type();
|
||||
const type = this.type();
|
||||
if (type === 'linear' && currentItem <= this.carouselItems().length - this.itemsPerPage) {
|
||||
this.carouselItemsTranslation(currentItem, `-${currentItem * 100}%`, this.direction());
|
||||
} else if (type === 'symmetric') {
|
||||
@@ -512,7 +510,7 @@ export class PiCarouselComponent
|
||||
|
||||
private setHorizontalCarouselStyle(): void {
|
||||
this.carouselItemsNativeElements.forEach((item) => {
|
||||
const itemWidth = this.itemWidth();
|
||||
const itemWidth = this.itemWidth();
|
||||
if (!!itemWidth) {
|
||||
this.renderer.setStyle(item, 'min-width', `${itemWidth}px`);
|
||||
this.renderer.setStyle(item, 'max-width', `${itemWidth}px`);
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, HostBinding, forwardRef, input, output } from '@angular/core';
|
||||
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
|
||||
import { NgIf, NgFor } from '@angular/common';
|
||||
import { PiIconComponent } from '../../icon/icon/icon.component';
|
||||
import { ChangeDetectionStrategy, Component, OnInit, HostBinding, forwardRef, input, model, output } from '@angular/core';
|
||||
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
|
||||
import { NgIf, NgFor } from '@angular/common';
|
||||
import { PiIconComponent } from '../../icon/icon/icon.component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'pi-paginator',
|
||||
templateUrl: './paginator.component.html',
|
||||
styleUrls: ['./paginator.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
PiIconButtonComponent,
|
||||
NgIf,
|
||||
NgFor,
|
||||
PiIconComponent,
|
||||
forwardRef(() => PiPaginatorComponent)
|
||||
],
|
||||
@Component({
|
||||
selector: 'pi-paginator',
|
||||
templateUrl: './paginator.component.html',
|
||||
styleUrls: ['./paginator.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
PiIconButtonComponent,
|
||||
NgIf,
|
||||
NgFor,
|
||||
PiIconComponent,
|
||||
forwardRef(() => PiPaginatorComponent)
|
||||
],
|
||||
})
|
||||
export class PiPaginatorComponent implements OnInit {
|
||||
@HostBinding('class') className = 'pi-paginator';
|
||||
readonly currentPage = input(1);
|
||||
readonly currentPage = model(1);
|
||||
readonly pageSize = input.required<number>();
|
||||
readonly totalPages = input.required<number>();
|
||||
readonly isDisabled = input.required<boolean>();
|
||||
@@ -65,7 +65,7 @@ export class PiPaginatorComponent implements OnInit {
|
||||
this.firstPages = this.decrementPaginatorRangeBy(3);
|
||||
this.firstPagesRange = this.firstPagesRange - 3;
|
||||
}
|
||||
this.currentPage = updatedCurrentPage;
|
||||
this.currentPage.set(updatedCurrentPage);
|
||||
this.changePage.emit(updatedCurrentPage);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export class PiPaginatorComponent implements OnInit {
|
||||
this.firstPagesRange = this.firstPagesRange + 3;
|
||||
this.firstPages = this.incrementPaginatorRangeBy(3);
|
||||
}
|
||||
this.currentPage = updatedCurrentPage;
|
||||
this.currentPage.set(updatedCurrentPage);
|
||||
this.changePage.emit(updatedCurrentPage);
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ export class PiPaginatorComponent implements OnInit {
|
||||
if (this.isDisabled() && selectedPage > this.currentPage()) {
|
||||
return;
|
||||
} else {
|
||||
this.currentPage = selectedPage;
|
||||
this.currentPage.set(selectedPage);
|
||||
this.changePage.emit(this.currentPage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SimpleChanges,
|
||||
TemplateRef,
|
||||
input,
|
||||
model,
|
||||
output,
|
||||
contentChild
|
||||
} from '@angular/core';
|
||||
@@ -59,7 +60,7 @@ export class PiExpansionPanelComponent extends PiBasePanelComponent implements O
|
||||
}
|
||||
|
||||
readonly type = input<'form' | 'custom'>('form');
|
||||
readonly isCollapsed = input(false);
|
||||
readonly isCollapsed = model(false);
|
||||
readonly title = input<string>();
|
||||
readonly subtitle = input<string>();
|
||||
readonly formGroup = input.required<FormGroup>();
|
||||
@@ -72,16 +73,16 @@ export class PiExpansionPanelComponent extends PiBasePanelComponent implements O
|
||||
readonly expandableContentRef = contentChild<TemplateRef<unknown>>('expandableContent');
|
||||
|
||||
override ngOnInit(): void {
|
||||
if (this.status() === 'disabled') this.isCollapsed = true;
|
||||
if (this.status() === 'disabled') this.isCollapsed.set(true);
|
||||
}
|
||||
|
||||
ngOnChanges({ status }: SimpleChanges): void {
|
||||
if (status?.currentValue === 'disabled') this.isCollapsed = true;
|
||||
if (status?.currentValue === 'disabled') this.isCollapsed.set(true);
|
||||
}
|
||||
|
||||
toggle(): void {
|
||||
const status = this.status();
|
||||
if (status !== 'disabled' && status !== 'info') this.isCollapsed = !this.isCollapsed();
|
||||
if (status !== 'disabled' && status !== 'info') this.isCollapsed.set(!this.isCollapsed());
|
||||
}
|
||||
|
||||
onEdit(): void {
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
Injector,
|
||||
QueryList,
|
||||
Renderer2,
|
||||
input
|
||||
} from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
||||
import _ from 'lodash';
|
||||
@@ -145,8 +145,8 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
|
||||
ngAfterContentInit(): void {
|
||||
this.control.setValue(this.selectedOption);
|
||||
merge(
|
||||
this.childrenOptionsComponents()?.changes || [],
|
||||
this.viewChildOptionsComponents()?.changes || [],
|
||||
toObservable(this.childrenOptionsComponents, { injector: this.injector }),
|
||||
toObservable(this.viewChildOptionsComponents, { injector: this.injector }),
|
||||
this.control.valueChanges
|
||||
).subscribe(() => {
|
||||
Promise.resolve().then(() => {
|
||||
@@ -180,9 +180,9 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
|
||||
*/
|
||||
private updateChildrenOptionsSelectedState(selectedOption: any): void {
|
||||
// Array of child option components to work with.
|
||||
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
|
||||
let childrenOptionsComponent: readonly PiSelectOptionComponent[];
|
||||
// Reference to the child option elements for DOM manipulation.
|
||||
let childrenOptionsElementRef: QueryList<ElementRef>;
|
||||
let childrenOptionsElementRef: readonly ElementRef[];
|
||||
|
||||
// Check if we have child options that are content projected from a parent component.
|
||||
const childrenOptionsComponents = this.childrenOptionsComponents();
|
||||
@@ -191,7 +191,7 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
|
||||
childrenOptionsElementRef = this.childrenOptionsEl();
|
||||
} else {
|
||||
// If not, it means they're internally defined (default), so we fetch from viewChildren.
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents;
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents();
|
||||
childrenOptionsElementRef = this.viewChildOptionsEl();
|
||||
}
|
||||
|
||||
@@ -202,12 +202,12 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
|
||||
: false;
|
||||
// If the current child option matches the selected option, highlight it.
|
||||
if (isSelected) {
|
||||
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-selected');
|
||||
this._renderer.addClass(childrenOptionsElementRef[index]?.nativeElement, 'is-selected');
|
||||
childOption.isSelected.set(true);
|
||||
} else {
|
||||
// Otherwise, ensure it is not highlighted.
|
||||
this._renderer.removeClass(
|
||||
childrenOptionsElementRef.get(index)?.nativeElement,
|
||||
childrenOptionsElementRef[index]?.nativeElement,
|
||||
'is-selected'
|
||||
);
|
||||
childOption.isSelected.set(false);
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Renderer2,
|
||||
input
|
||||
} from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
||||
import { merge } from 'rxjs';
|
||||
@@ -164,8 +165,8 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
ngAfterContentInit(): void {
|
||||
this.control.setValue(this.selectedOptions);
|
||||
merge(
|
||||
this.childrenOptionsComponents()?.changes || [],
|
||||
this.viewChildOptionsComponents()?.changes || [],
|
||||
toObservable(this.childrenOptionsComponents, { injector: this.injector }),
|
||||
toObservable(this.viewChildOptionsComponents, { injector: this.injector }),
|
||||
this.control.valueChanges
|
||||
).subscribe(() => {
|
||||
Promise.resolve().then(() => {
|
||||
@@ -244,9 +245,9 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
*/
|
||||
private updateChildrenOptionsSelectedState(selectedOptions: any[]): void {
|
||||
// Array of child option components to work with.
|
||||
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
|
||||
let childrenOptionsComponent: readonly PiSelectOptionComponent[];
|
||||
// Reference to the child option elements for DOM manipulation.
|
||||
let childrenOptionsElementRef: QueryList<ElementRef>;
|
||||
let childrenOptionsElementRef: readonly ElementRef[];
|
||||
|
||||
// Check if we have child options that are content projected from a parent component.
|
||||
const childrenOptionsComponents = this.childrenOptionsComponents();
|
||||
@@ -255,7 +256,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
childrenOptionsElementRef = this.childrenOptionsEl();
|
||||
} else {
|
||||
// If not, it means they're internally defined (default), so we fetch from viewChildren.
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents;
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents();
|
||||
childrenOptionsElementRef = this.viewChildOptionsEl();
|
||||
}
|
||||
|
||||
@@ -264,11 +265,11 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
(selectedOption) => selectedOption[this.keyIdProperty()] === childOption['id']
|
||||
);
|
||||
if (isSelected) {
|
||||
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-selected');
|
||||
this._renderer.addClass(childrenOptionsElementRef[index]?.nativeElement, 'is-selected');
|
||||
childOption.isSelected.set(true);
|
||||
} else {
|
||||
this._renderer.removeClass(
|
||||
childrenOptionsElementRef.get(index)?.nativeElement,
|
||||
childrenOptionsElementRef[index]?.nativeElement,
|
||||
'is-selected'
|
||||
);
|
||||
childOption.isSelected.set(false);
|
||||
@@ -295,9 +296,9 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
// Disable all options if the maximum number of selections has been reached.
|
||||
const disableOthers = selectedOptions.length >= (this.maxLength() || Infinity);
|
||||
// Array of child option components to work with.
|
||||
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
|
||||
let childrenOptionsComponent: readonly PiSelectOptionComponent[];
|
||||
// Reference to the child option elements for DOM manipulation.
|
||||
let childrenOptionsElementRef: QueryList<ElementRef>;
|
||||
let childrenOptionsElementRef: readonly ElementRef[];
|
||||
|
||||
// Check if we have child options that are content projected from a parent component.
|
||||
const childrenOptionsComponents = this.childrenOptionsComponents();
|
||||
@@ -306,7 +307,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
childrenOptionsElementRef = this.childrenOptionsEl();
|
||||
} else {
|
||||
// If not, it means they're internally defined (default), so we fetch from viewChildren.
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents;
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents();
|
||||
childrenOptionsElementRef = this.viewChildOptionsEl();
|
||||
}
|
||||
|
||||
@@ -317,10 +318,10 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
|
||||
|
||||
const isDisabled = childOption.isDisabled();
|
||||
if ((!isSelected && disableOthers) || isDisabled) {
|
||||
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-disabled');
|
||||
this._renderer.addClass(childrenOptionsElementRef[index]?.nativeElement, 'is-disabled');
|
||||
} else {
|
||||
this._renderer.removeClass(
|
||||
childrenOptionsElementRef.get(index)?.nativeElement,
|
||||
childrenOptionsElementRef[index]?.nativeElement,
|
||||
'is-disabled'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
HostBinding,
|
||||
HostListener,
|
||||
Injector,
|
||||
QueryList,
|
||||
Renderer2,
|
||||
input
|
||||
} from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
||||
import { merge } from 'rxjs';
|
||||
@@ -161,8 +161,8 @@ export class PiSelectPeriodComponent extends PiBaseSelectComponent implements Af
|
||||
ngAfterContentInit(): void {
|
||||
this.control.setValue(this.selectedOption);
|
||||
merge(
|
||||
this.childrenOptionsComponents()?.changes || [],
|
||||
this.viewChildOptionsComponents()?.changes || [],
|
||||
toObservable(this.childrenOptionsComponents, { injector: this.injector }),
|
||||
toObservable(this.viewChildOptionsComponents, { injector: this.injector }),
|
||||
this.control.valueChanges
|
||||
).subscribe(() => {
|
||||
Promise.resolve().then(() => {
|
||||
@@ -192,9 +192,9 @@ export class PiSelectPeriodComponent extends PiBaseSelectComponent implements Af
|
||||
*/
|
||||
private updateChildrenOptionsSelectedState(selectedOption: any): void {
|
||||
// Array of child option components to work with.
|
||||
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
|
||||
let childrenOptionsComponent: readonly PiSelectOptionComponent[];
|
||||
// Reference to the child option elements for DOM manipulation.
|
||||
let childrenOptionsElementRef: QueryList<ElementRef>;
|
||||
let childrenOptionsElementRef: readonly ElementRef[];
|
||||
|
||||
// Check if we have child options that are content projected from a parent component.
|
||||
const childrenOptionsComponents = this.childrenOptionsComponents();
|
||||
@@ -203,7 +203,7 @@ export class PiSelectPeriodComponent extends PiBaseSelectComponent implements Af
|
||||
childrenOptionsElementRef = this.childrenOptionsEl();
|
||||
} else {
|
||||
// If not, it means they're internally defined (default), so we fetch from viewChildren.
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents;
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents();
|
||||
childrenOptionsElementRef = this.viewChildOptionsEl();
|
||||
}
|
||||
|
||||
@@ -214,12 +214,12 @@ export class PiSelectPeriodComponent extends PiBaseSelectComponent implements Af
|
||||
: false;
|
||||
// If the current child option matches the selected option, highlight it.
|
||||
if (isSelected) {
|
||||
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-selected');
|
||||
this._renderer.addClass(childrenOptionsElementRef[index]?.nativeElement, 'is-selected');
|
||||
childOption.isSelected.set(true);
|
||||
} else {
|
||||
// Otherwise, ensure it is not highlighted.
|
||||
this._renderer.removeClass(
|
||||
childrenOptionsElementRef.get(index)?.nativeElement,
|
||||
childrenOptionsElementRef[index]?.nativeElement,
|
||||
'is-selected'
|
||||
);
|
||||
childOption.isSelected.set(false);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, Injector, QueryList, Renderer2, forwardRef, input } from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
||||
import { merge } from 'rxjs';
|
||||
@@ -151,8 +152,8 @@ export class PiSelectComponent extends PiBaseSelectComponent implements AfterCon
|
||||
ngAfterContentInit(): void {
|
||||
this.control.setValue(this.selectedOption);
|
||||
merge(
|
||||
this.childrenOptionsComponents()?.changes || [],
|
||||
this.viewChildOptionsComponents()?.changes || [],
|
||||
toObservable(this.childrenOptionsComponents, { injector: this.injector }),
|
||||
toObservable(this.viewChildOptionsComponents, { injector: this.injector }),
|
||||
this.control.valueChanges
|
||||
).subscribe(() => {
|
||||
Promise.resolve().then(() => {
|
||||
@@ -182,9 +183,9 @@ export class PiSelectComponent extends PiBaseSelectComponent implements AfterCon
|
||||
*/
|
||||
private updateChildrenOptionsSelectedState(selectedOption: any): void {
|
||||
// Array of child option components to work with.
|
||||
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
|
||||
let childrenOptionsComponent: readonly PiSelectOptionComponent[];
|
||||
// Reference to the child option elements for DOM manipulation.
|
||||
let childrenOptionsElementRef: QueryList<ElementRef>;
|
||||
let childrenOptionsElementRef: readonly ElementRef[];
|
||||
|
||||
// Check if we have child options that are content projected from a parent component.
|
||||
const childrenOptionsComponents = this.childrenOptionsComponents();
|
||||
@@ -193,7 +194,7 @@ export class PiSelectComponent extends PiBaseSelectComponent implements AfterCon
|
||||
childrenOptionsElementRef = this.childrenOptionsEl();
|
||||
} else {
|
||||
// If not, it means they're internally defined (default), so we fetch from viewChildren.
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents;
|
||||
childrenOptionsComponent = this.viewChildOptionsComponents();
|
||||
childrenOptionsElementRef = this.viewChildOptionsEl();
|
||||
}
|
||||
|
||||
@@ -204,11 +205,11 @@ export class PiSelectComponent extends PiBaseSelectComponent implements AfterCon
|
||||
: false;
|
||||
// If the current child option matches the selected option, highlight it.
|
||||
if (isSelected) {
|
||||
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-selected');
|
||||
this._renderer.addClass(childrenOptionsElementRef[index]?.nativeElement, 'is-selected');
|
||||
childOption.isSelected.set(true);
|
||||
} else { // Otherwise, ensure it is not highlighted.
|
||||
this._renderer.removeClass(
|
||||
childrenOptionsElementRef.get(index)?.nativeElement,
|
||||
childrenOptionsElementRef[index]?.nativeElement,
|
||||
'is-selected'
|
||||
);
|
||||
childOption.isSelected.set(false);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import {
|
||||
AfterViewChecked,
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Renderer2,
|
||||
effect,
|
||||
input,
|
||||
output,
|
||||
contentChildren,
|
||||
@@ -37,7 +36,7 @@ import { TranslatePipe } from '@ngx-translate/core';
|
||||
TranslatePipe,
|
||||
],
|
||||
})
|
||||
export class PiTabComponent implements AfterViewInit, AfterViewChecked, OnDestroy {
|
||||
export class PiTabComponent implements AfterViewChecked, OnDestroy {
|
||||
@HostBinding('class') get classes(): string {
|
||||
const appearanceClass = `pi-tab__appearance--${this.appearance()}`;
|
||||
const hideTabsClass = this.hideTabs() ? 'hide-tabs' : '';
|
||||
@@ -106,11 +105,9 @@ export class PiTabComponent implements AfterViewInit, AfterViewChecked, OnDestro
|
||||
return isTabWrapperOverflowing;
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.tabContentItems().changes.subscribe(() => {
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
}
|
||||
// El ngAfterViewInit original sólo suscribía a tabContentItems.changes para
|
||||
// hacer markForCheck(); como ahora es una signal query, Angular ya reevalúa
|
||||
// la plantilla cuando cambia.
|
||||
|
||||
ngAfterViewChecked(): void {
|
||||
this.cdr.detectChanges();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, HostBinding, OnChanges, SimpleChanges, input } from '@angular/core';
|
||||
import { Directive, HostBinding, input } from '@angular/core';
|
||||
|
||||
@Directive({ selector: '[pi-text-centered]', })
|
||||
export class PiTextCenteredDirective {
|
||||
@@ -14,17 +14,13 @@ export class PiTextGroupDirective {
|
||||
}
|
||||
}
|
||||
@Directive({ selector: '[pi-disabled]', })
|
||||
export class PiDisabledDirective implements OnChanges {
|
||||
export class PiDisabledDirective {
|
||||
@HostBinding('style.opacity') get opacity(): number {
|
||||
return this.isDisabled() ? 0.2 : 1;
|
||||
}
|
||||
// El ngOnChanges original sólo reasignaba a la entrada su propio
|
||||
// currentValue (no-op). Con signal inputs sobra.
|
||||
readonly isDisabled = input<boolean>();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes) {
|
||||
this.isDisabled = changes['isDisabled'].currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ selector: '[pi-covered]', })
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
import { Directive, OnChanges, HostBinding, SimpleChanges, input } from '@angular/core';
|
||||
|
||||
@Directive({ selector: '[pi-disabled]', })
|
||||
export class PiDisabledDirective implements OnChanges {
|
||||
@HostBinding('style.opacity') get opacity(): number {
|
||||
return this.isDisabled() ? 0.33 : 1;
|
||||
}
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isDisabled() && 'is-disabled'].join(' ');
|
||||
}
|
||||
|
||||
readonly isDisabled = input<boolean>();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes) {
|
||||
this.isDisabled = changes['isDisabled'].currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ selector: '[is-active]', })
|
||||
export class PiIsActiveDirective {
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isActive() ? 'is-active' : '', 'pi-status'].join(' ');
|
||||
}
|
||||
|
||||
readonly isActive = input.required<boolean>();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes) {
|
||||
this.isActive = changes['isActive'].currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ selector: '[is-visited]', })
|
||||
export class PiIsVisitedDirective {
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isVisited() ? 'is-visited' : '', 'pi-status'].join(' ');
|
||||
}
|
||||
|
||||
readonly isVisited = input.required<boolean>();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes) {
|
||||
this.isVisited = changes['isVisited'].currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
import { Directive, HostBinding, input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Los `ngOnChanges` originales sólo reasignaban a la entrada su propio
|
||||
* `currentValue`, es decir, eran no-ops. Con signal inputs sobran.
|
||||
*/
|
||||
|
||||
@Directive({ selector: '[pi-disabled]', })
|
||||
export class PiDisabledDirective {
|
||||
@HostBinding('style.opacity') get opacity(): number {
|
||||
return this.isDisabled() ? 0.33 : 1;
|
||||
}
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isDisabled() && 'is-disabled'].join(' ');
|
||||
}
|
||||
|
||||
readonly isDisabled = input<boolean>();
|
||||
}
|
||||
|
||||
@Directive({ selector: '[is-active]', })
|
||||
export class PiIsActiveDirective {
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isActive() ? 'is-active' : '', 'pi-status'].join(' ');
|
||||
}
|
||||
|
||||
readonly isActive = input.required<boolean>();
|
||||
}
|
||||
|
||||
@Directive({ selector: '[is-visited]', })
|
||||
export class PiIsVisitedDirective {
|
||||
@HostBinding('class') get classes(): string | boolean {
|
||||
return [this.isVisited() ? 'is-visited' : '', 'pi-status'].join(' ');
|
||||
}
|
||||
|
||||
readonly isVisited = input.required<boolean>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user