Formularze oparte na szablonach
Najprostszym podejściem do tworzenia formularzy w Angular jest użycie typowych struktur wywodzących się z HTML:
<form method="POST" action="/register" id="signup-form">
<label for="email">Email</label>
<input type="text" name="email" id="email">
<label for="password">Password</label>
<input type="password" name="password" id="password">
<button type="submit">Sign Up</button>
</form>
Do podstawowej implementacji wystarczy dodać kilka atrybutów i upewnić się, że nasz komponent wie, co zrobić z danymi.
index.html
<signup-form>Loading...</signup-form>
signup-form.component.html
<form #signupForm="ngForm" (ngSubmit)="registerUser(signupForm)">
<label for="email">Email</label>
<input type="text" name="email" id="email" ngModel>
<label for="password">Password</label>
<input type="password" name="password" id="password" ngModel>
<button type="submit">Sign Up</button>
</form>
signup-form.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'signup-form',
templateUrl: 'signup-form.component.html',
})
export class SignupFormComponent {
registerUser(form: NgForm) {
console.log(form.value);
// {email: '...', password: '...'}
// ...
}
}
Zagnieżdżanie formularzy
Angular ułatwia dopasowanie zagnieżdżonego drzewa danych do płaskiego formularza.
Załóżmy, że masz punkt końcowy płatności, który wymaga danych, podobny do następującego:
{
"contact": {
"firstname": "Bob",
"lastname": "McKenzie",
"email": "BobAndDoug@GreatWhiteNorth.com",
"phone": "555-TAKE-OFF"
},
"address": {
"street": "123 Some St",
"city": "Toronto",
"region": "ON",
"country": "CA",
"code": "H0H 0H0"
},
"paymentCard": {
"provider": "Credit Lending Company Inc",
"cardholder": "Doug McKenzie",
"number": "123 456 789 012",
"verification": "321",
"expiry": "2020-02"
}
}
Podczas gdy formularze są płaskie i jednowymiarowe, dane z których je budujemy nie są. Chcąc uniknąć kolizji nazw, tworzymy długie i niezręczne nazwy.
<form>
<fieldset>
<legend>Contact</legend>
<label for="contact_first-name">First Name</label>
<input type="text" name="contact_first-name" id="contact_first-name">
<label for="contact_last-name">Last Name</label>
<input type="text" name="contact_last-name" id="contact_last-name">
<label for="contact_email">Email</label>
<input type="email" name="contact_email" id="contact_email">
<label for="contact_phone">Phone</label>
<input type="text" name="contact_phone" id="contact_phone">
</fieldset>
<!-- ... -->
</form>
Moduł obsługi formularzy musiałby przekonwertować te dane na formularz oczekiwany przez interfejs API. Na szczęście jest to coś, na co Angular ma rozwiązanie.
ngModelGroup
Podczas budowania formularza sterowanego szablonami w Angular, możemy oprzeć się na dyrektywie ngModelGroup
, aby osiągnąć czystszą implementację, podczas gdy Angular wykonuje intensywne przekształcanie pól formularzy w zagnieżdżone dane.
<form #paymentForm="ngForm" (ngSubmit)="purchase(paymentForm)">
<fieldset ngModelGroup="contact">
<legend>Contact</legend>
<label>
First Name <input type="text" name="firstname" ngModel>
</label>
<label>
Last Name <input type="text" name="lastname" ngModel>
</label>
<label>
Email <input type="email" name="email" ngModel>
</label>
<label>
Phone <input type="text" name="phone" ngModel>
</label>
</fieldset>
<fieldset ngModelGroup="address">
<!-- ... -->
</fieldset>
<fieldset ngModelGroup="paymentCard">
<!-- ... -->
</fieldset>
</form>
- Korzystanie z alternatywnego formatu etykietowania HTML5; Identyfikatory nie mają wpływu na paradygmat
ngForm
/ngModel
ngModelGroup
nie musi być używane w<fieldset>
- może to równie dobrze być<div>
.
Po wypełnieniu tak zdefiniowanego formularza, otrzymamy dane, w strukturze odpowiedniej dla naszego API.
Powiązania modelu i szablonu
Wiązanie jednokierunkowe
Jeśli potrzebujesz formularza z wartościami domyślnymi, możesz zacząć używać składni wiążącej wartość dla ngModel.
app/signup-form.component.html
<form #signupForm="ngForm" (ngSubmit)="register(signupForm)">
<label for="username">Username</label>
<input type="text" name="username" id="username" [ngModel]="generatedUser">
<label for="email">Email</label>
<input type="email" name="email" id="email" ngModel>
<button type="submit">Sign Up</button>
</form>
app/signup-form.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
// ...
@Component({
// ...
})
export class SignupFormComponent {
generatedUser: string = generateUniqueUserID();
register(form: NgForm) {
console.log(form.value);
// ...
}
}
Dwukierunkowe wiązanie
Chociaż Angular domyślnie przyjmuje wiązanie jednokierunkowe, wiązanie dwukierunkowe jest nadal dostępne.
Aby mieć dostęp do dwukierunkowego wiązania w formularzach opartych na szablonach, użyj składni:[(ngModel)] = propertyName .
Pamiętaj, aby zadeklarować wszystkie właściwości, które będą potrzebne w komponencie.
<form #signupForm="ngForm" (ngSubmit)="register(signupForm)">
<label for="username">Username</label>
<input type="text" name="username" id="username" [(ngModel)]="username">
<label for="email">Email</label>
<input type="email" name="email" id="email" [(ngModel)]="email">
<button type="submit">Sign Up</button>
</form>
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
// ...
})
export class SignUpFormComponent {
username: string = generateUniqueUserID();
email = '';
register(form: NgForm) {
console.log(form.value.username);
console.log(this.username);
// ...
}
}
Sprawdzanie poprawności formularzy opartych na szablonach
Sprawdzanie poprawności możemy definiować następująco:
<!-- a required field -->
<input type="text" required>
<!-- an optional field of a specific length -->
<input type="text" pattern=".{3,8}">
<!-- a non-optional field of specific length -->
<input type="text" pattern=".{3,8}" required>
<!-- alphanumeric field of specific length -->
<input type="text" pattern="[A-Za-z0-9]{0,5}">
Zauważ, że atrybut pattern
jest mniej wydajną wersją składni RegEx języka JavaScript.
Istnieją inne atrybuty HTML5, które można zastosować do różnych typów danych wejściowych; jednak w większości przypadków działają one jako górne i dolne limity, co zapobiega dodawaniu lub usuwaniu dodatkowych informacji.
<!-- a field which will accept no more than 5 characters -->
<input type="text" maxlength="5">
Podczas pisania formularza opartego na szablonie można użyć jednej lub obu tych metod.