在Angular 2中构建表单最直接的方法是利用为您提供的指令。
首先,考虑一个典型的表单:
<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>
Angular 2已经为你提供了一个form
指令,并形成在封面下操作的相关指令,如输入等。 对于基本的实现,我们只需要添加一些属性,并确保我们的组件知道如何处理数据。
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: 'app-signup-form',
templateUrl: 'app/signup-form.component.html',
})
export class SignupFormComponent {
registerUser(form: NgForm) {
console.log(form.value);
// {email: '...', password: '...'}
// ...
}
}
嵌套表单数据
如果你发现你在把一维的表单替换成嵌套的数据上遇到了麻烦,不用怕,Angular已经涵盖了简单和复杂的情况。假设你要提交一个类似下面的数据:
{
"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"
}
}
虽然表单是平面和一维的,但从它们构建的数据不是。将您已经提供的数据转换为所需的形状, 这会导致复杂的变换。
更糟的是,在可能在表单输入中遇到命名冲突的情况下,您可能会发现自己为了语义而使用长而笨拙的名称。
<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>
表单处理程序必须将该数据转换为API期望的表单。 幸运的是,这是Angular 2有一个解决方案。
ngModelGroup
当在Angular 2中构建模板驱动的表单时,我们可以依靠ngModelGroup
指令来实现一个更干净的实现,这样Angular就会将表单字段转换为嵌套数据。
<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>
- 使用替代HTML5标签格式; ID与
ngForm
/ngModelparadigm
没有关系- 除了语义目的,ngModelGroup不必在
<fieldset>
上使用,它会和放在<div>
上一样。
如果我们填写表单,它将以我们需要的API的形式结束,而且仍然可以依靠HTML进行验证。
单向绑定
如果您需要具有默认值的表单,可以开始使用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 SignupForm {
generatedUser: string = generateUniqueUserID();
register(form: NgForm) {
console.log(form.value);
// ...
}
}
双向绑定
虽然Angular 2默认情况下假定单向绑定,但如果需要,双向绑定仍然可用。为了能够访问模板驱动表单中的双向绑定,请使用“Banana-Box”语法([(ngModel)] ="propertyName")
。请务必声明组件上需要的所有属性。
<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 SignUpForm {
username: string = generateUniqueUserID();
email: string = '';
register(form: NgForm) {
console.log(form.value.username);
console.log(this.username);
// ...
}
}
验证模板驱动的表单
验证
验证模板驱动的表单,下面是使用HTML5的做法:
<!-- 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}">
请注意,pattern
属性是JavaScript RegEx语法的一个不太强大的版本。还有其他HTML5属性,可以学习和应用于各种类型的输入; 然而在大多数情况下,它们作为上限和下限,防止添加或删除额外信息。
<!-- a field which will accept no more than 5 characters -->
<input type="text" maxlength="5">
在编写模板驱动表单时,可以使用这两种方法之一。 关注用户体验:在某些情况下,防止意外输入是有意义的,在其他情况下,允许不受限制的输入是有意义的,但提供类似计数器的东西以显示限制。
下一节:在我们的模板中使用指令给我们没有太多的样板快速原型的能力,我们被束缚住了。 相反,响应式表单,让我们通过代码定义我们的形式,并给我们对数据验证更多的灵活性和控制。
首先,在它的简便性上有一点魔法,但是在你熟悉基础知识之后,学习它的构建块将允许你处理更复杂的用例。