Nazad na blog
Miloš Krstić3 min čitanja

Custom form polje uz Signal Forme

Custom form polje uz Signal Forme
Kliknite na sliku za uvećanje

Godinama smo se oslanjali na Control Value Accessor.

Sa Signal Formama dolazi novi interfejs koji treba da implementiramo.

Od ControlValueAccessor do FormValueControl

Sa klasičnim Reactive Forms, ako ste želeli custom polje u formi (date picker, rich text editor, dropdown, itd.), morali ste da:

  • implementirate ControlValueAccessor
  • registrujete ga sa NG_VALUE_ACCESSOR
  • ručno implementirate writeValue, registerOnChange, setDisabledState, itd.

Sa Signal Formama, ugovor se prebacuje na interfejse umesto neprozirnih callback-ova:

  • FormUiControl — opcioni UI/status inputi (errors, disabled, touched, itd.)
  • FormValueControl<TValue> — glavni ugovor za kontrole koje menjaju vrednost

Ako vaša komponenta implementira FormValueControl<TValue>, Field direktiva zna kako da poveže polje sa njom.

Šta ovi interfejsi zaista znače

FormUiControl

Ovo je set inputa koje je "lepo imati". Svaki property je:

  • opcion
  • InputSignal<…> (ili slično)
  • automatski povezan od strane Field direktive ako je prisutan

Primeri:

errors?: InputSignal<ValidationError[]>

→ Ako ga implementirate, Field će gurnuti validacione greške u vašu komponentu.

disabled?: InputSignal<boolean>

→ Ako je implementirano, vaša komponenta će primati true/false na osnovu stanja polja.

touched?, dirty?, invalid?, pending?, required?, min, max, minLength, maxLength, pattern, itd.
→ Sve ovo omogućava pravljenje super pametnih custom komponenti koje u potpunosti reflektuju stanje polja bez vašeg ručnog povezivanja.

Možete implementirati nijednu, neke, ili sve od ovih. Samo value je obavezan — a to se nalazi na sledećem interfejsu.

FormValueControl<TValue>

Ovo je osnovni ugovor za "normalno" custom polje:

interface FormValueControl<TValue> extends FormUiControl {
  readonly value: ModelSignal<TValue>;
  readonly checked?: undefined;
}

Ključne tačke:

  • value: ModelSignal<TValue> je obavezan
    → Ovo je dvosmerno povezivanje (two-way binding) između vaše komponente i forme.
  • checked?: undefined je ovde eksplicitno zabranjen
    → To je rezervisano za drugačiji ugovor (komponente u stilu checkbox-a).

Dakle:

Ako vaša komponenta ima value model signal, može se koristiti sa [field].

Bez writeValue, bez registerOnChange, bez provajdera. Samo model signal.

Minimalni primer: Custom input sa Signal Formama

Zamislite jednostavnu custom input komponentu:

import { Component, model, input } from '@angular/core';
import { Field } from '@angular/forms/signals';
import type { FormValueControl } from '@angular/forms/signals';

@Component({
  selector: 'app-fancy-input',
  standalone: true,
  template: `
    <label class="flex flex-col gap-1">
      <span class="text-sm font-medium">Fancy input</span>
      <input
        class="border rounded px-3 py-2"
        [value]="value()"
        (input)="value.set($any($event.target).value)"
        [disabled]="disabled() ?? false"
      />
    </label>
  `,
})
export class FancyInputComponent implements FormValueControl<string> {
  // obavezno za FormValueControl
  readonly value = model<string>('');

  // opciono, iz FormUiControl — Field će ih povezati ako su prisutni
  readonly errors = input<ReadonlyArray<{ message: string }> | undefined>();
  readonly disabled = input<boolean>();
  readonly invalid = input<boolean>();
}

Zatim to možete koristiti u Signal Formi na sledeći način:

import { Component, signal } from '@angular/core';
import { form, Field } from '@angular/forms/signals';
import { FancyInputComponent } from './fancy-input.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [Field, FancyInputComponent],
  template: `
    <form>
      <app-fancy-input [field]="form.name"></app-fancy-input>
    </form>
  `,
})
export class AppComponent {
  private readonly model = signal({ name: '' });

  protected readonly form = form(this.model);
}

To je to. Nema CVA, nema NG_VALUE_ACCESSOR.

Imate sličan frontend problem?

Zatražite Frontend Dijagnozu
  • Identifikujte uska grla u performansama
  • Uočite probleme u arhitekturi
  • Dobijte konkretne preporuke
Pokreni Besplatnu Analizu