NOTE: Bu kılavuz, Signal Forms temelleri konusuna aşinalık olduğunu varsayar.
Tarayıcının yerleşik form kontrolleri (input, select, textarea gibi) yaygın durumları karşılar, ancak uygulamalar genellikle özelleştirilmiş girdilere ihtiyaç duyar. Takvim arayüzüne sahip bir tarih seçici, biçimlendirme araç çubuğuna sahip bir zengin metin düzenleyici veya otomatik tamamlamalı bir etiket seçici, hepsi özel uygulamalar gerektirir.
Signal Forms, belirli arayüzleri uygulayan herhangi bir bileşenle çalışır. Bir kontrol arayüzü, bileşeninizin form sistemiyle iletişim kurmasını sağlayan özellikleri ve sinyalleri tanımlar. Bileşeniniz bu arayüzlerden birini uyguladığında, [formField] direktifi kontrolünüzü otomatik olarak form durumu, doğrulama ve veri bağlamaya bağlar.
Temel bir özel kontrol oluşturma
Minimal bir uygulama ile başlayalım ve ihtiyaç duydukça özellikler ekleyelim.
Minimal girdi kontrolü
Temel bir özel girdi yalnızca FormValueControl arayüzünü uygulamak ve gerekli value model sinyalini tanımlamak zorundadır.
import {Component, model} from '@angular/core';
import {FormValueControl} from '@angular/forms/signals';
@Component({
selector: 'app-basic-input',
template: `
<div class="basic-input">
<input
type="text"
[value]="value()"
(input)="value.set($event.target.value)"
placeholder="Enter text..."
/>
</div>
`,
})
export class BasicInput implements FormValueControl<string> {
/** Geçerli girdi değeri */
value = model('');
}
Minimal onay kutusu kontrolü
Bir onay kutusu tarzı kontrol iki şeye ihtiyaç duyar:
FormFielddirektifinin onu bir form kontrolü olarak tanıması içinFormCheckboxControlarayüzünü uygulaması- Bir
checkedmodel sinyali sağlaması
import {Component, model, ChangeDetectionStrategy} from '@angular/core';
import {FormCheckboxControl} from '@angular/forms/signals';
@Component({
selector: 'app-basic-toggle',
template: `
<button type="button" [class.active]="checked()" (click)="toggle()">
<span class="toggle-slider"></span>
</button>
`,
})
export class BasicToggle implements FormCheckboxControl {
/** Geçiş düğmesinin işaretli olup olmadığı */
checked = model<boolean>(false);
toggle() {
this.checked.update((val) => !val);
}
}
Özel kontrolünüzü kullanma
Bir kontrol oluşturduktan sonra, FormField direktifini ekleyerek yerleşik bir girdi kullanacağınız her yerde kullanabilirsiniz:
import {Component, signal, ChangeDetectionStrategy} from '@angular/core';
import {form, FormField, required} from '@angular/forms/signals';
import {BasicInput} from './basic-input';
import {BasicToggle} from './basic-toggle';
@Component({
imports: [FormField, BasicInput, BasicToggle],
template: `
<form novalidate>
<label>
Email
<app-basic-input [formField]="registrationForm.email" />
</label>
<label>
Accept terms
<app-basic-toggle [formField]="registrationForm.acceptTerms" />
</label>
<button type="submit" [disabled]="registrationForm().invalid()">Register</button>
</form>
`,
})
export class Registration {
registrationModel = signal({
email: '',
acceptTerms: false,
});
registrationForm = form(this.registrationModel, (schemaPath) => {
required(schemaPath.email, {message: 'Email is required'});
required(schemaPath.acceptTerms, {message: 'You must accept the terms'});
});
}
NOTE: Şema geri çağırma parametresi (bu örneklerde schemaPath), formunuzdaki tüm alanlara yollar sağlayan bir SchemaPathTree nesnesidir. Bu parametreyi istediğiniz gibi adlandırabilirsiniz.
[formField] direktifi, özel kontroller ve yerleşik girdiler için aynı şekilde çalışır. Signal Forms bunlara aynı şekilde davranır - doğrulama çalışır, durum güncellenir ve veri bağlama otomatik olarak gerçekleşir.
Kontrol arayüzlerini anlama
Özel kontrolleri çalışırken gördüğünüze göre, şimdi Signal Forms ile nasıl entegre olduklarını inceleyelim.
Kontrol arayüzleri
Oluşturduğunuz BasicInput ve BasicToggle bileşenleri, Signal Forms'a onlarla nasıl etkileşim kuracağını söyleyen belirli kontrol arayüzlerini uygular.
FormValueControl
FormValueControl, çoğu girdi türü için arayüzdür - metin girdileri, sayı girdileri, tarih seçiciler, seçim açılır menüleri ve tek bir değeri düzenleyen herhangi bir kontrol. Bileşeniniz bu arayüzü uyguladığında:
- Gerekli özellik: Bileşeniniz bir
valuemodel sinyali sağlamalıdır - FormField direktifinin yaptığı: Form alanının değerini kontrolünüzün
valuesinyaline bağlar
IMPORTANT: FormValueControl uygulayan kontrollerde checked özelliği bulunmamalıdır
FormCheckboxControl
FormCheckboxControl, onay kutusu benzeri kontroller için arayüzdür - geçiş düğmeleri, anahtarlar ve boolean açık/kapalı durumunu temsil eden herhangi bir kontrol. Bileşeniniz bu arayüzü uyguladığında:
- Gerekli özellik: Bileşeniniz bir
checkedmodel sinyali sağlamalıdır - FormField direktifinin yaptığı: Form alanının değerini kontrolünüzün
checkedsinyaline bağlar
IMPORTANT: FormCheckboxControl uygulayan kontrollerde value özelliği bulunmamalıdır
İsteğe bağlı durum özellikleri
Hem FormValueControl hem de FormCheckboxControl, form durumuyla entegrasyon için isteğe bağlı özellikler sağlayan temel arayüz FormUiControl'ü genişletir.
Tüm özellikler isteğe bağlıdır. Yalnızca kontrolünüzün ihtiyaç duyduklarını uygulayın.
Etkileşim durumu
Kullanıcıların kontrolünüzle ne zaman etkileşim kurduğunu takip edin:
| Property | Purpose |
|---|---|
touched |
Kullanıcının alanla etkileşim kurup kurmadığı |
dirty |
Değerin başlangıç durumundan farklı olup olmadığı |
Doğrulama durumu
Kullanıcılara doğrulama geri bildirimi gösterin:
| Property | Purpose |
|---|---|
errors |
Mevcut doğrulama hatalarının dizisi |
valid |
Alanın geçerli olup olmadığı |
invalid |
Alanın doğrulama hataları olup olmadığı |
pending |
Asenkron doğrulamanın devam edip etmediği |
Kullanılabilirlik durumu
Kullanıcıların alanınızla etkileşim kurup kuramayacağını kontrol edin:
| Property | Purpose |
|---|---|
disabled |
Alanın devre dışı olup olmadığı |
disabledReasons |
Alanın neden devre dışı olduğunun nedenleri |
readonly |
Alanın salt okunur olup olmadığı (görünür ama düzenlenemez) |
hidden |
Alanın görünümden gizli olup olmadığı |
NOTE: disabledReasons, DisabledReason nesnelerinden oluşan bir dizidir. Her nesnenin bir field özelliği (alan ağacına referans) ve isteğe bağlı bir message özelliği vardır. Mesaja reason.message üzerinden erişin.
Doğrulama kısıtlamaları
Formdan doğrulama kısıtlama değerlerini alın:
| Property | Purpose |
|---|---|
required |
Alanın zorunlu olup olmadığı |
min |
Minimum sayısal değer (kısıtlama yoksa undefined) |
max |
Maksimum sayısal değer (kısıtlama yoksa undefined) |
minLength |
Minimum dize uzunluğu (kısıtlama yoksa undefined) |
maxLength |
Maksimum dize uzunluğu (kısıtlama yoksa undefined) |
pattern |
Eşleştirilecek düzenli ifade kalıpları dizisi |
Alan metadata'sı
| Property | Purpose |
|---|---|
name |
Alanın name niteliği (formlar ve uygulamalar genelinde benzersizdir) |
Aşağıdaki "Adding state signals" bölümü, bu özelliklerin kontrollerinizde nasıl uygulanacağını gösterir.
FormField direktifi nasıl çalışır
[formField] direktifi, kontrolünüzün hangi arayüzü uyguladığını algılar ve uygun sinyalleri otomatik olarak bağlar:
import {Component, signal, ChangeDetectionStrategy} from '@angular/core';
import {form, FormField, required} from '@angular/forms/signals';
import {CustomInput} from './custom-input';
import {CustomToggle} from './custom-toggle';
@Component({
selector: 'app-my-form',
imports: [FormField, CustomInput, CustomToggle],
template: `
<form novalidate>
<app-custom-input [formField]="userForm.username" />
<app-custom-toggle [formField]="userForm.subscribe" />
</form>
`,
})
export class MyForm {
formModel = signal({
username: '',
subscribe: false,
});
userForm = form(this.formModel, (schemaPath) => {
required(schemaPath.username, {message: 'Username is required'});
});
}
TIP: Form modellerini oluşturma ve yönetme konusunda kapsamlı bilgi için Form Models kılavuzuna bakın.
[formField]="userForm.username" bağladığınızda, FormField direktifi:
- Kontrolünüzün
FormValueControluyguladığını algılar - Dahili olarak
userForm.username().value()değerine erişir ve bunu kontrolünüzünvaluemodel sinyaline bağlar - Form durum sinyallerini (
disabled(),errors(), vb.) kontrolünüzün isteğe bağlı girdi sinyallerine bağlar - Güncellemeler sinyal reaktivitesi aracılığıyla otomatik olarak gerçekleşir
Durum sinyalleri ekleme
Yukarıda gösterilen minimal kontroller çalışır, ancak form durumuna tepki vermezler. Kontrollerinizin devre dışı durumuna tepki vermesi, doğrulama hatalarını göstermesi ve kullanıcı etkileşimini izlemesi için isteğe bağlı girdi sinyalleri ekleyebilirsiniz.
İşte yaygın durum özelliklerini uygulayan kapsamlı bir örnek:
import {Component, model, input, ChangeDetectionStrategy} from '@angular/core';
import {
FormValueControl,
WithOptionalFieldTree,
ValidationError,
DisabledReason,
} from '@angular/forms/signals';
@Component({
selector: 'app-stateful-input',
template: `
@if (!hidden()) {
<div class="input-container">
<input
type="text"
[value]="value()"
(input)="value.set($event.target.value)"
[disabled]="disabled()"
[readonly]="readonly()"
[class.invalid]="invalid()"
[attr.aria-invalid]="invalid()"
(blur)="touched.set(true)"
/>
@if (invalid()) {
<div class="error-messages" role="alert">
@for (error of errors(); track error) {
<span class="error">{{ error.message }}</span>
}
</div>
}
@if (disabled() && disabledReasons().length > 0) {
<div class="disabled-reasons">
@for (reason of disabledReasons(); track reason) {
<span>{{ reason.message }}</span>
}
</div>
}
</div>
}
`,
})
export class StatefulInput implements FormValueControl<string> {
// Gerekli
value = model<string>('');
// Yazılabilir etkileşim durumu - kontrol bunları günceller
touched = model<boolean>(false);
// Salt okunur durum - form sistemi bunları yönetir
disabled = input<boolean>(false);
disabledReasons = input<readonly DisabledReason[]>([]);
readonly = input<boolean>(false);
hidden = input<boolean>(false);
invalid = input<boolean>(false);
errors = input<readonly WithOptionalFieldTree<ValidationError>[]>([]);
}
Sonuç olarak, kontrolü doğrulama ve durum yönetimi ile kullanabilirsiniz:
import {Component, signal, ChangeDetectionStrategy} from '@angular/core';
import {form, FormField, required, email} from '@angular/forms/signals';
import {StatefulInput} from './stateful-input';
@Component({
imports: [FormField, StatefulInput],
template: `
<form novalidate>
<label>
Email
<app-stateful-input [formField]="loginForm.email" />
</label>
</form>
`,
})
export class Login {
loginModel = signal({email: ''});
loginForm = form(this.loginModel, (schemaPath) => {
required(schemaPath.email, {message: 'Email is required'});
email(schemaPath.email, {message: 'Enter a valid email address'});
});
}
Kullanıcı geçersiz bir e-posta yazdığında, FormField direktifi invalid() ve errors() değerlerini otomatik olarak günceller. Kontrolünüz doğrulama geri bildirimini gösterebilir.
Durum özellikleri için sinyal türleri
Çoğu durum özelliği input() (formdan salt okunur) kullanır. Kontrolünüz kullanıcı etkileşiminde güncellediğinde touched için model() kullanın. touched özelliği, ihtiyaçlarınıza bağlı olarak benzersiz bir şekilde model(), input() veya OutputRef desteği sunar.
Değer dönüşümü
Kontroller bazen değerleri form modelinin sakladığından farklı şekilde görüntüler - bir tarih seçici "2024-01-15" saklarken "15 Ocak 2024" gösterebilir veya bir para birimi girdisi 1234.56 saklarken "$1,234.56" gösterebilir.
Model değerini görüntüleme için dönüştürmek üzere linkedSignal() (@angular/core'dan) kullanın ve kullanıcı girdisini depolama biçimine geri ayrıştırmak için girdi olaylarını işleyin:
import {formatCurrency} from '@angular/common';
import {ChangeDetectionStrategy, Component, linkedSignal, model} from '@angular/core';
import {FormValueControl} from '@angular/forms/signals';
@Component({
selector: 'app-currency-input',
template: `
<input
type="text"
[value]="displayValue()"
(input)="displayValue.set($event.target.value)"
(blur)="updateModel()"
/>
`,
})
export class CurrencyInput implements FormValueControl<number> {
// Sayısal değeri saklar (1234.56)
readonly value = model.required<number>();
// Görüntüleme değerini saklar ("1,234.56")
readonly displayValue = linkedSignal(() => formatCurrency(this.value(), 'en', 'USD'));
// Görüntüleme değerinden modeli güncelle.
updateModel() {
this.value.set(parseCurrency(this.displayValue()));
}
}
// Bir para birimi dizesini sayıya dönüştürür (ör. "USD1,234.56" -> 1234.56).
function parseCurrency(value: string): number {
return parseFloat(value.replace(/^[^\d-]+/, '').replace(/,/g, ''));
}
Doğrulama entegrasyonu
Kontroller doğrulama durumunu görüntüler ancak doğrulama gerçekleştirmez. Doğrulama form şemasında gerçekleşir - kontrolünüz FormField direktifinden invalid() ve errors() sinyallerini alır ve bunları görüntüler (yukarıdaki StatefulInput örneğinde gösterildiği gibi).
FormField direktifi ayrıca required, min, max, minLength, maxLength ve pattern gibi doğrulama kısıtlama değerlerini de iletir. Kontrolünüz bunları arayüzü geliştirmek için kullanabilir:
export class NumberInput implements FormValueControl<number> {
value = model<number>(0);
// Şema doğrulama kurallarından kısıtlama değerleri
required = input<boolean>(false);
min = input<number | undefined>(undefined);
max = input<number | undefined>(undefined);
}
Şemaya min() ve max() doğrulama kuralları eklediğinizde, FormField direktifi bu değerleri kontrolünüze iletir. Bunları HTML5 nitelikleri uygulamak veya şablonunuzda kısıtlama ipuçları göstermek için kullanın.
IMPORTANT: Kontrolünüzde doğrulama mantığı uygulamayın. Doğrulama kurallarını form şemasında tanımlayın ve kontrolünüzün sonuçları göstermesini sağlayın:
// Kaçının: Kontrolde doğrulama
export class BadControl implements FormValueControl<string> {
value = model<string>('');
isValid() {
return this.value().length >= 8;
} // Bunu yapmayın!
}
// İyi: Şemada doğrulama, kontrol sonuçları gösterir
accountForm = form(this.accountModel, (schemaPath) => {
minLength(schemaPath.password, 8, {message: 'Password must be at least 8 characters'});
});
Sonraki adımlar
Bu kılavuz, Signal Forms ile entegre olan özel kontroller oluşturmayı ele aldı. İlgili kılavuzlar Signal Forms'un diğer yönlerini inceler: