Angular Reactive Forms – How to dynamically change validation based on a service state

Discussão em 'Angular' iniciado por Dima Savenkov, Fevereiro 25, 2025.

  1. I have an Angular component with local dependencies: SecureService and LoginFormModel.

    • SecureService is used to work with secure information
    • LoginFormModel is responsible for reactive form management

    The data initially comes encrypted (with a string length of more than 1000 characters) and is masked for the user. When I switch from view mode to edit mode, I decrypt values, and max length validation (250 characters) should be applied. Currently, the form is initially invalid because the enxrypted data exceeds the validation limit.

    Code Example

    LoginFormModel

    export class LoginFormModel {
    private fb = inject(FormBuilder);

    public readonly form: FormGroup<LoginForm> = this.createForm();

    public setFormValues(loginData: LoginsResponse): void {
    this.form.reset();
    this.setData(loginData);
    }

    private createForm(): FormGroup<LoginForm> {
    return this._fb.group({
    password: [null, Validators.compose([CustomValidators.requiredInput(), Validators.maxLength(250)])],
    username: [null, Validators.compose([CustomValidators.requiredInput(), Validators.maxLength(250)])],
    }) as FormGroup<LoginForm>;
    }

    private setData(loginData: LoginsResponse): void {
    this.form.patchValue({
    password: loginData.password,
    username: loginData.username,
    });
    }


    LoginFormComponent

    import { Component } from '@angular/core';
    import { SecureService } from './secure.service';
    import { LoginFormModel } from './login-form.model';

    @Component({
    selector: 'form',
    template: `
    <form [formGroup]="formModel.form">
    <input type="text" formControlName="password" placeholder="Password">
    <input type="text" formControlName="username" placeholder="Username">
    </form>
    <button (click)="toggleEncryption()">Toggle Encryption</button>
    `,
    providers: [SecureService, LoginFormModel] // Local instances
    })
    export class LoginFormComponent {
    constructor(public formModel: LoginFormModel, private secureService: SecureService) {}

    toggleEncryption() {
    this.secureService.toggleEncryption();
    }
    }


    SecureService

    @Injectable()
    export class SecureService {
    private _isEncrypted = signal<boolean>(true);
    public isSecureGroupEncrypted$$ = computed(() => this._isEncrypted());

    toggleEncryption() {
    this._isEncrypted.set(!this._isEncrypted());
    }
    }


    Right now, I simply disable the secure fields when isSecureGroupEncrypted$$() is true, which effectively skips validation. When encryption is disabled (isSecureGroupEncrypted$$() === false), I enable the fields and apply max length validation (250 characters).

    Would it be better to use a custom validator that dynamically applies max length validation when encryption is off?

    If so, how should I inject SecureService into the validator and ensure it reacts to isSecureGroupEncrypted$$ state changes?

    Since SecureService is a local instance, I need the same instance to be available in both LoginFormComponent and LoginFormModel.

    • Should I manually create the LoginFormModel instance and resolve dependencies via a factory?
    • Or should I pass SecureService as a parameter inside createForm()?
    • Or is it simpler to just continue using enable/disable logic instead of a validator?

    Continue reading...

Compartilhe esta Página