angular / angular/angular

Creating custom CVA based components is STILL almost impossible to in most not-super-basic scenarios (regardless the unified event api)

Abierto
#57,972 7 comentarios 0 reacciones 0 asignados Ver en GitHub
area: forms
Lenguaje dominante
TypeScript
Estrellas
101k
Forks
27.5k
Merge medio
1 d 19 h
PR fusionados (30 d)
288

Descripción

### Which @angular/* package(s) are relevant/related to the feature request?

forms

### Description

It is still impossible to implement working custom CVA based components in 50% of scenarios.

Main cause of this is non-existing way how to get ALL information about AbstractControl.

Why?
- there is not any 100% working way how to get information about important control state (valid/invalid/pristine/touched).
- it is important to know control states like valid/invalid/pristine/touched to correctly implement smarter components than hello world

Why current implementation does not work?

- CVA interface does not provide ANY way how to get information about status changes (it can only react to ValueChanges - writevalue and disabled changes - setDisabled), there is not anything like setValid(), setTouched() pristine etc.

- You can get ngControl from injector (because CVA is solving only 20% of domain...) .Control has now "unified events api" https://angular.dev/api/forms/AbstractControl#events unfortunately, it is preserved when {emitEvent: false} during the method calls

- It is EVEN BIGGER Problem as far as disabled control has BOTH valid and invalid SET TO FALSE (lol), so you just DO NOT HAVE ANY way how to get any information about the state of validity, when your control is enabled with {emitEvent:false} (check source code below)

- it is so sad that the only way how to get 100% information about control state is to LISTEN for DOM mutation on Host element (to read ng-invalid, ng-valid, ng-pending, ng-prisitine, etc. classes)
- the same problem when validity of the control changes when the new value is set - you have NO WAY how to get the new valid / invalid status when user patch/set value with emitEvent: false. You cannot even handle this inside of writeValue() because validators are executed after that.... So not any workaround..

FORCING user not to use {emitEvent:false } which is his way to prevent emiting valueChanges "ON THE OUTSIDE SIDE" - aka. consumer of the component (in bigger form) is definitely not a solution to this problem, where Component creator has not any legit way how to get state of the control.

```

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

import { FormControl, PristineChangeEvent, ReactiveFormsModule, StatusChangeEvent, TouchedChangeEvent} from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
selector: 'app-root',
standalone: true,
imports: [ReactiveFormsModule, CommonModule],
template: `

Valid: {{number.valid}}
Invalid: {{number.invalid}}
Errors: {{number.errors | json}}

ENABLE



Problems:

  • Disabled input has both VALID and INVALID set TRUE - eventhogh there is no validator and it NO ERRORS

  • When you enable control - it is now valid, but NO events is fired from Control.Events



Events:

    @for(event of events; track $index) {
  • {{event | json}}

  • }

`,
})
export class App {

events: any[] =[];
number = new FormControl();

ngOnInit( ){
this.number.disable();
this.number.events.subscribe(e=> {
if (e instanceof StatusChangeEvent) {
this.events.push("Status - " + e.status);
} else if (e instanceof TouchedChangeEvent) {
this.events.push("Touched - "+ e.touched);
} else if (e instanceof PristineChangeEvent) {
this.events.push("Pristine - "+ e.pristine);
}
}
);
}
}

bootstrapApplication(App);

```

### Proposed solution

- more methods in CVA interface
- event emitter on AbstractControl which emits everytime, regardless the emitEvent settings

### Alternatives considered

- our only WAY how to solve this is to write our own AbstractControl's implementations (inherit the base ones from angular) and to add additional event emiiters...
- in this case where is the main problem the valid/invalid state of control, you can "rebind" your internal valid/invalid/pristine/touched state when setDisabled() of CVA is called.
- in case of changed valid/invalid state when the new value is set to control with emitEvent:false, there is not any way except to "queue" sync check after "writeValue"

image

Just sad state.

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Comienza con la reproducción proporcionada e inspecciona la Angular forms CVA interface, el estado de AbstractControl y el comportamiento de AbstractControl.events en torno a disable/enable y emitEvent:false. Compara los CVA methods propuestos y el AbstractControl event emitter incondicional con las forms APIs existentes; done debe definirse mediante tests que cubran la validez del control y la visibilidad de su estado en custom CVA components.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
angular, typescript
Área
frontend
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Tranquilo
Claridad
Necesita aclaración
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.