typescript - Angular @Input establecido programáticamente para controles de terceros
Estoy usando controles PrimeNG. Estoy configurando el atributo deshabilitado en varios controles de entrada a través de una directiva y algunos de los controles son p-dropdown, p-listbox y p-calendar de PrimeNG. Los controles básicos de entrada, textarea y select funcionan bien, pero los controles PrimeNG tienen disable definido como @Input de la siguiente manera:
private _disabled: boolean;
@Input() get disabled(): boolean {
return this._disabled;
};
y un fragmento de código de la directiva es el siguiente:
/*
** find all inputs and disable them.
*/
disableElements( el: ElementRef ): void {
const controls = el.nativeElement.querySelectorAll( 'input, select, textarea, p-dropdown, p-listbox, p-checkbox' );
controls.forEach( (elmt: any) => {
this.disableElement( elmt );
});
}
/*
** disable an input element.
*/
disableElement( elmt: any ): void {
if( elmt.localName.substr(0,2) === 'p-' ) {
this._renderer.setProperty(elmt, 'disabled', 'true');
} else {
if(!elmt.hasAttribute('disabled')) {
this._renderer.setAttribute(elmt, 'disabled', 'true');
}
}
}
Entonces, ¿cómo deshabilitar los controles de terceros de PrimeNG dado un ElementRef.nativeElement? Estoy pensando que necesito una manera de cumplir con la propiedad @Input disabled dado una referencia a un elemento.
Respuesta #1
Básicamente, no creo que sea una buena idea deshabilitar controles programáticamente usando una directiva, te recomiendo totalmente manejarlo usando los buenos y viejos inputs en su lugar.
Pero puedo proponer la siguiente solución para su situación: https://stackblitz.com/edit/angular-disable-prime-ng-elements
La solución en sí no es perfecta, pero es un compromiso si no quieres trabajar con entradas deshabilitadas.
- En primer lugar, crea una directiva llamada
PrimeNgComponentsChangeDetectorRefDirectivepara obtener una versión pública del detector de cambios de los componentes de primeng y actualizar sus vistas. Debes incluir manualmente todos los componentes de primeng que deseas manejar. El truco aquí es usar el mismo selector para coincidir automáticamente con los componentes de primeng.
@Directive({
selector: 'p-checkbox, p-dropdown, p-listbox'
})
export class PrimeNgComponentsChangeDetectorRefDirective {
public hostComponent: Checkbox | Dropdown | Listbox;
constructor(
public cdr: ChangeDetectorRef,
@Optional() private checkbox: Checkbox,
@Optional() private dropdown: Dropdown,
@Optional() private listbox: Listbox
) {}
ngAfterViewInit() {
this.hostComponent = this.getHostComponent();
}
private getHostComponent() {
return [this.checkbox, this.dropdown, this.listbox].find(
component => !!component
);
}
}
- Luego, en su directiva de desactivación implemente las siguientes propiedades y métodos:
@ContentChildren(PrimeNgComponentsChangeDetectorRefDirective)
private componentsQuery: QueryList<
PrimeNgComponentsChangeDetectorRefDirective
>;
disablePrimeNgComponents() {
const components = this.componentsQuery.toArray();
components.forEach(component => {
component.hostComponent.disabled = true;
component.cdr.detectChanges();
});
}
Necesitamos detectChanges manualmente porque hemos cambiado la propiedad disabled programáticamente y Angular no sabe nada sobre este cambio.
