Angular 18 custom input: FormControl has strange behavior

Discussão em 'Angular' iniciado por Foreigner, Outubro 30, 2024.

  1. Foreigner

    Foreigner Guest

    I'm struggling with some strange behavior while using my custom input component.

    First of all, I built a simple abstract class that has the main "features" and methods of the component, then, the input-component which has very few code:

    // Abstract class

    export abstract class BaseFormInput<T> implements ControlValueAccessor, Validator, AfterViewInit, OnDestroy {
    @Input() label: string
    @Output() onChange: EventEmitter<T> = new EventEmitter<T>()

    private changeInternal: (obj: T) => void
    private changeSub: Subscription
    private disabled$ = new BehaviorSubject(false)
    private required$ = new BehaviorSubject(false)

    public input = new FormControl(null)

    ngOnDestroy() {
    this.changeSub.unsubscribe()
    }

    ngAfterViewInit() {
    this.changeSub = this.input.valueChanges.subscribe(v => {
    if (!this.disabled$.getValue()) {
    this.onChange.emit(v)
    this.changeInternal(v)
    }
    })
    }

    writeValue = (obj: T) => this.input.setValue(obj)

    registerOnChange = (fn: (obj: T) => void) => this.changeInternal = fn

    registerOnTouched = (_fn: (obj: any) => void) => {}

    setDisabledState = (isDisabled: boolean) => this.disabled$.next(isDisabled)

    validate(control: AbstractControl): ValidationErrors {
    this.required$.next(control.hasValidator(Validators.required))

    // THIS LINE HAS WEIRD BEHAVIOR
    console.log(control, control.errors)

    return null
    }

    public get isDisabled$(){
    return this.disabled$.asObservable()
    }

    public get isRequired$(){
    return this.required$.asObservable()
    }
    }


    The input component is simply designed like this:

    @Component({
    selector: "ec-input-text",
    template: `<div class="form-control">
    <label *ngIf="label">
    {{ label }}
    <span *ngIf="isRequired$ | async">*</span>
    </label>
    <input *ngIf="type !== 'textarea'" [type]="type" [formControl]="input" [attr.disabled]="isDisabled$ | async" />
    <textarea *ngIf="type === 'textarea'" [formControl]="input" [attr.disabled]="isDisabled$ | async"></textarea>
    <ng-template></ng-template>
    </div>`,
    changeDetection: ChangeDetectionStrategy.OnPush,
    providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputTextComponent), multi: true },
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => InputTextComponent), multi: true }
    ]
    })
    export class InputTextComponent extends BaseFormInput<string> {
    @Input() type: "text" | "password" | "email" | "textarea" = "text"
    @Input() maxLength: number
    }


    Finally, I created a register-component, which uses the input.

    HTML:

    <form [formGroup]="form">
    <ec-input-text label="First name" formControlName="firstName" />
    <ec-input-text label="Last name" formControlName="lastName" />
    <ec-input-text label="E-mail" formControlName="email" type="email" />
    <ec-input-text label="Password" formControlName="password" type="password" />
    </form>


    The TS of the register-component has a public property like this:

    public form = new FormGroup({
    firstName: new FormControl(null, [Validators.required, Validators.maxLength(50)]),
    lastName: new FormControl(null, [Validators.required, Validators.maxLength(50)]),
    email: new FormControl(null, [Validators.required, Validators.maxLength(100)]),
    password: new FormControl(null, Validators.required)
    })


    Now, the issue is the following: in the validate method of the abstract class (where I put a comment), I tried to log the control errors, and I get a strange behavior: when logging the formControl, I can see in the console that the property errors is null, but if I log control.errors it logs:

    { required: true }


    Even though the control is valid and I typed the value (in fact, control.value has a value and results valid). So if i do:

    console.log(control)


    And I expand it, errors is null (expected behavior, correct!)

    But if I do:

    console.log(control.errors)


    It is valorized (not correct, the control is valid!)

    How can I figure this out? Thanks in advance!

    Continue reading...

Compartilhe esta Página