Búsqueda de sitios web

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.

  1. En primer lugar, crea una directiva llamada PrimeNgComponentsChangeDetectorRefDirective para 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
    );
  }
}
  1. 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.

Artículos relacionados