Angular 中模板驱动表单和反应表单之间的区别
介绍
表单是任何应用中非常常见的功能。在本指南中,我们将了解 Angular 用于创建表单的两种技术 - 模板驱动和响应式表单。我们还将了解如何使用这两种方法添加验证。
模板驱动表单和反应式表单之间的高层次差异
以下是两种类型之间的一些高层差异:
- 模板驱动表单使用“FormsModule”,而反应表单基于“ReactiveFormsModule”。
- 模板驱动表单本质上是异步的,而反应式表单大多是同步的。
- 在模板驱动方法中,大多数逻辑由模板驱动,而在反应驱动方法中,逻辑主要位于组件或 TypeScript 代码中。让我们先生成一个组件,然后更新表单代码。
为表单创建组件
我们将使用以下命令为这两种类型生成单独的组件:
ng generate component template-forms
ng generate component reactive-forms
模板驱动表单
为了启用模板驱动表单,即为了让 ngModel 和其他与表单相关的指令可用于我们的项目,我们必须将它们显式导入到我们的 AppModule 中。添加导入后,我们的 app.module.ts 应该是这样的:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule} from '@angular/forms';
import { AppComponent } from './app.component';
import { TemplateFormsComponent } from './template-forms.component';
@NgModule({
declarations: [
AppComponent,
TemplateFormsComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
现在,我们已经准备好表单的基本设置,让我们开始添加表单代码。
我们有一个添加新课程的屏幕。以下是该模板的外观:
<div class="row">
<div class="col-xs-12">
<form>
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control">
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control">
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button">Clear</button>
</div>
</div>
</form>
</div>
</div>
我们创建了包含课程名称、课程描述和金额字段的基本 HTML 表单,并且还有用于添加、删除或清除表单的按钮。
虽然 Angular 能够检测到上述代码中的<form>元素(因为我们已在 app.module.ts 中导入了 FormsModule),但我们需要手动注册表单控件。为此,我们需要向表单控件添加“ngModel”,并向控件添加“name”属性。“ngModel”会将我们的输入字段绑定到数据模型上的属性。此外,为了提交表单,我们将使用 (ngSubmit) 指令,该指令会在提交表单时触发。
更新后的 HTML 看起来如下:
<div class="row">
<div class="col-xs-12">
<form (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
name="courseName"
ngModel>
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
name="courseDesc"
ngModel>
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
name="courseAmount"
ngModel>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button">Clear</button>
</div>
</div>
</form>
</div>
</div>
如果我们想为任何字段(例如课程名称)分配任何默认值,我们可以绑定到 ngModel,如下所示:
<input
type="text"
id="courseName"
class="form-control"
name="courseName"
[ngModel]="'default course name'">
现在我们已经创建了表单,让我们尝试提交表单。我们还将向表单添加一些基本验证(例如,我们将课程名称输入字段标记为必填)。此外,我们将在表单元素上添加本地引用,以便我们可以在 Typescript 代码中访问表单。
<div class="row">
<div class="col-xs-12">
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
name="courseName"
ngModel
required>
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
name="courseDesc"
ngModel>
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
name="courseAmount"
ngModel>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button" (click)="onClear()">Clear</button>
</div>
</div>
</form>
</div>
</div>
现在我们已经为表单提交定义了处理程序,让我们在 Typescript 组件中添加代码来处理此问题。当用户单击“清除”按钮时,我们还将重置表单。为此,我们将通过 @ViewChild 在 Typescript 代码中访问表单。下面是我们的组件 Typescript 代码的样子:
import {
Component,
OnInit,
OnDestroy
} from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-template-forms',
templateUrl: './template-forms.component.html',
styleUrls: ['./template-forms.component.css']
})
export class TemplateFormsComponent implements OnInit, OnDestroy {
constructor() { }
ngOnInit() {
}
@ViewChild('f') courseForm: NgForm;
onSubmit(form: NgForm) {
console.log("Course Name is : " + form.value.courseName);
console.log("Course Desc is : " + form.value.courseDesc);
console.log("Course Amount is : " + form.value.courseAmount);
}
onClear() {
// Now that we have access to the form via the 'ViewChild', we can access the form and clear it.
this.courseForm.reset();
}
onDelete() {
}
ngOnDestroy() {
}
}
Thus, we can see that an object of type "NgForm" gets created and we can access the values which the user entered by accessing them on the "value" property.
最后,让我们添加代码,如果用户未输入必填字段(此处为课程名称),则显示错误消息。另外,请记住,默认情况下不应显示此错误,即在表单加载时,而应仅在用户未输入任何值的情况下退出时显示。因此,我们将使用“dirty”和“touched”属性。让我们看看相关的模板代码:
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
name="courseName"
ngModel
required
#courseName="ngModel">
</div>
<div style="color:red"
*ngIf="courseName.errors && (courseName.dirty || courseName.touched)">
<p *ngIf="courseName.errors.required">
Course Name is required
</p>
</div>
因此,我们只是为验证消息添加了一个 div 元素。仅当我们的 courseName 字段上存在验证错误时,才会呈现 div 元素上的 *ngIf,该字段实际上指向 ngModel 实例。此外,我们希望仅当我们的 courseName 字段脏污或被触碰时才显示此 div。在该 div 内,我们可以通过访问 courseName.errors 属性为不同类型的错误添加更多验证,例如在本例中,我们正在检查 courseName.errors.required。
响应式表单
现在让我们看看另一种方法 - 反应式表单,也称为模型驱动表单。在这种方法中,我们在组件(Typescript 代码)中设计表单,然后将它们绑定或关联到我们的 HTML 模板。它们需要在 app.module.ts 中导入“ReactiveFormsModule”。因此,这就是我们的反应式表单的 AppModule 的样子。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule} from '@angular/forms';
import { AppComponent } from './app.component';
import { ReactiveFormsComponent } from './reactive-forms.component';
@NgModule({
declarations: [
AppComponent,
ReactiveFormsComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
现在让我们从表单开始。我们将尝试使用相同的示例来添加课程。让我们首先从我们的 TypeScript 代码开始。在这里我们将定义 FormGroup 类的新实例,并在其中使用 FormControl 类定义我们的控件。以下是我们的组件代码:
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.css']
})
export class ReactiveFormsComponent implements OnInit {
courseForm: FormGroup;
constructor() {
}
ngOnInit() {
this.initForm();
}
onSubmit() {
}
private initForm() {
this.courseForm = new FormGroup({
'courseName': new FormControl(null, Validators.required),
'courseDesc': new FormControl(null),
'courseAmount': new FormControl(null)
});
}
}
因此,我们创建了“FormGroup”的新实例并将其分配给组件上的“courseForm”属性。我们还使用“FormControl”类定义了表单控件。我们可以将控件的默认值定义为第一个参数。在上面的例子中,我们将其定义为 null(空字段)。
由于我们希望课程名称字段是必填字段,因此我们将“Validators.required”作为“courseName”表单控件的第二个参数传递。如果我们想使用任何异步验证(例如检查数据库中是否已存在 courseName,我们可以使用第三个参数来定义异步验证)。
但是,此时 Angular 还不知道我们的哪些 Typescript 控件与模板代码中的哪些输入相关。我们利用模板中的“formControlName”指令将模板中的各个控件与 FormGroup 实例上的控件关联起来。
我们的模板如下所示:
<div class="row">
<div class="col-xs-12">
<form [formGroup]="courseForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
formControlName="courseName">
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
formControlName="courseDesc">
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
formControlName="courseAmount">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button">Clear</button>
</div>
</div>
</form>
</div>
</div>
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~