NgxControlValueAccessor es una directiva para reducir la redundancia al construir componentes que implementan la interfaz ControlValueAccessor.
Importar
Sección titulada «Importar»import { NgxControlValueAccessor } from 'ngxtension/control-value-accessor';NgxControlValueAccessor implementa la interfaz ControlValueAccessor y expone una api más simple. Declara NgxControlValueAccessor en la sección hostDirectives de tu componente e inyecta la instancia para conectar tu plantilla:
NgxControlValueAccessor.valuepara sincronizar el valor.NgxControlValueAccessor.disabledpara sincronizar el estado deshabilitado.NgxControlValueAccessor.markAsTouchedpara marcar la vista como touched.
El valor y el estado deshabilitado también están disponibles como señales:
NgxControlValueAccessor.value$NgxControlValueAccessor.disabled$
Ejemplo
Sección titulada «Ejemplo»En este ejemplo, NgxControlValueAccessor se utiliza para crear un componente CustomInput.
@Component({ selector: 'custom-input', hostDirectives: [NgxControlValueAccessor], template: ` <label> <b>Etiqueta personalizada</b> <input type="text" (input)="cva.value = $event.target.value" [value]="cva.value$()" [disabled]="cva.disabled$()" (blur)="cva.markAsTouched()" /> </label> `, standalone: true,})export class CustomInput { protected cva = inject<NgxControlValueAccessor<string>>( NgxControlValueAccessor, );}Con el uso:
<custom-input [formControl]="control" /><custom-input [(ngModel)]="value" />Valores no primitivos
Sección titulada «Valores no primitivos»Cuando tu modelo es un tipo de dato no primitivo, debes proporcionar un comparador. Es una función pura que le dice a NgxControlValueAccessor si dos valores son semánticamente iguales:
(a, b) => boolean;Ejemplo
Sección titulada «Ejemplo»En este ejemplo, NgxControlValueAccessor se utiliza para crear un selector de Usuario. Un Usuario se identifica por su id.
interface Usuario { id: string; nombre: string;}
const comparadorUsuario: NgxControlValueAccessorCompareTo<Usuario> = (a, b) => a?.id === b?.id;
provideCvaCompareTo(comparadorUsuario, true);
// o
provideCvaCompareToByProp<Usuario>('id');Ejemplo completo:
@Component({ selector: 'selector-usuario', standalone: true, hostDirectives: [NgxControlValueAccessor], providers: [provideCvaCompareToByProp<Usuario>('id')], template: ` <label> <b>Selecciona un usuario:</b> <select [disabled]="cva.disabled$()" (blur)="cva.markAsTouched()" (change)="onChange($event)" > <option [selected]="cva.value === null"> -- ningún usuario seleccionado -- </option> @for (usuario of usuarios; track usuario.id) { <option [value]="usuario.id" [selected]="usuario.id === cva.value?.id" > {{ usuario.nombre }} </option> } </select> </label> `,})export class SelectorUsuario { protected cva = inject<NgxControlValueAccessor<Usuario | null>>( NgxControlValueAccessor, );
protected onChange = (event: Event) => (this.cva.value = this.usuarios.find(({ id }) => event.target.value === id) ?? null);
@Input() usuarios: Usuario[] = [];}Con uso:
<selector-usuario [formControl]="controlUsuario" [usuarios]="usuarios" /><selector-usuario [(ngModel)]="usuario" [usuarios]="usuarios" />Sin NgControl
Sección titulada «Sin NgControl»Opcionalmente, puedes exponer inputs y outputs en la declaración de hostDirectives y usarlo sin una directiva NgControl.
hostDirectives: [ { directiva: NgxControlValueAccessor, inputs: ['value'], outputs: ['valueChange'], },];<custom-input [(value)]="valor" />