RAHUL KUNDU
RAHUL KUNDU

Reputation: 881

Angular computed signal not reflecting changes when input signal changes

I am using Angular signals with Reactive Forms and facing an issue where the hasFormControlError and validations computed signals are not updating the view when the formControl input signal value changes. I am passing reactive form control instances in the formControl signal input,

The issue here is computed signals reflecting updates in the view only when submitted, but if the control is dirty, invalid at the time of key press, even the errors object nothing is reflecting in the view by the computed signals.

However, if I change them to getters, they work fine and reflecting everything. I am unable to understand why this is happening what i am doing wrong here.

Stackblitz - https://stackblitz.com/edit/stackblitz-starters-ur795u?file=src%2Fmain.ts

This is how i am passing the form control instance from parent

<form-control [form-control]="formControls()['email']"></form-control>
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { fadeAnimation } from '@shared/animations';
import { generateNumericId } from '@shared/utilities';
import { AbstractControl, FormControl } from '@angular/forms';
import { FormControlValidationService } from '../../services';
import { IControlConfig, IFormControlValidation } from '../../models';
import { Component, computed, inject, input, output } from '@angular/core';

@Component({
    standalone: true,
    selector: 'form-control',
    animations: [fadeAnimation],
    imports: [CommonModule, FormsModule],
    styleUrl: './form-control.component.css',
    providers: [FormControlValidationService],
    templateUrl: './form-control.component.html'
})
export class FormControlComponent {
    private _validationService = inject(FormControlValidationService);

    
    public formControl = input.required<AbstractControl | FormControl>({
        alias: 'form-control',
    });

    
    public controlConfig = input({}, {
        alias: 'control-config',
        transform: (value: IControlConfig) => {
            return {
                isRequired: true,
                showErrorMessages: true,
                ...value
            };
        }
    });


    
    public hasFormControlError = computed<boolean>(() => {
        return !!(
            (this.formControl().invalid && this.formControl().dirty) ||
            (this.controlConfig().submitted && this.formControl().errors)
        );
    });

    
    public validations = computed<IFormControlValidation[]>(() => {
        return Object.keys(this.formControl().errors || {}).map((key) => {
            const validationError = {
                errorType: key,
                errorMessage: '',
                id: generateNumericId(),
                formControl: this.formControl(),
                error: this.formControl().errors?.[key]
            };

            validationError['errorMessage'] =
                this._validationService.getControlErrorMessage(validationError);

            return validationError;
        });
    });

    
}

Upvotes: 3

Views: 2124

Answers (1)

Kobi Hari
Kobi Hari

Reputation: 1248

If you expect the computed signal to be recalculated, than of course it does not. The reactive nature of signals is based on the signals ability to notice that its value changed. But the form control does not change. It is still the same reference. Yes, the values inside its properties change, but the signal does not know it, so it does not "signal".

When you use signals, you need to store immutable data in them. If you use normal objects, that mutate, then the signal will not be aware of it, and computed signals will not be recalculated. (also, effects will not re-execute).

What you could do, is receive the form control as normal input, and then convert their statusChanges observable into a signal using the toSignal method.

As a side note - reactive forms is probably the only core angular feature that is not based on the same paradigm as signals. They currently do not work so well together. I believe the angular team will provide an alternative approach to forms that is based on immutable data.

Upvotes: 0

Related Questions