简单记录一下最近学习的Angular Form相关知识,并实现一个「编辑-显示」Demo。
Form简介
Angular包含两种类型的form,分别是Reactive forms与Template-driven forms。两者异同以及适用场景在这里有详细介绍。
Reactive forms与Template-driven forms在实现层面最大的不同在于:
- Reactive forms是在html元素中添加
[formControl]
directive,然后在ts文件中显式地新建一个实例,如下:
html:
<input type="text" [formControl]="xxxControl">
typescript:
...
export class XComponent {
xxxControl = new FormControl('I am an init value');
}
- Template-driven forms是在html中添加[(ngModel)],ngModel的名字与类属性名相同,
FormControl
的实例被隐式创建。
html:
<input type="text" [(ngModel)]="xxxControl">
typescript:
...
export class XComponent {
xxxControl = 'I am an init value';
}
Angular的一大特点就是view与model的双向绑定,也就是说html的DOM元素与对应的model始终是同步的。页面input
值改变,对应的xxxControl
值也改变。
如果想通过model更改view,对于Reactive forms,只需要this.xxxControl.setValue('new value')
;对于Template forms,只需要this.xxxControl = 'new value'
,view上的显示就会随之更改。
Reactive forms keep the data model pure by providing it as an immutable data structure. Each time a change is triggered on the data model, the
FormControl
instance returns a new data model rather than updating the existing data model.
Template-driven forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template.
了解到这些,就可以实现一个简单的demo。
Demo实现
这个Demo最终的效果是:
- 第一次进入页面,显示两个标签(其实被
disabled
的input),分别是姓名与星座。
- 点击被
disabled
的input,会出现apply按钮与cancel按钮, 同时input变为可编辑状态,用户可以随意输入姓名与星座。
-
点击apply,input被disabled,同时显示修改后的值
-
点击cancel,input仍然显示上次显示的值。
-
分析
- 页面上有两套控件,分别是一组可以与用户交互的input,以及一组被当作标签使用的disabled input。可以使用一个变量editMode控制显示哪一组input,如果是可编辑的,则显示可交互的input,否则显示disabled input;
- 初始状态显示的是disabled input,包括name与zodiac sign两个input,两者的默认值可以内置在代码中,或从其他地方读取;而可交互的那组默认值则设置为从disabled input上取值,name与zodiac sign分别取对应的值;
- 点击apply后,disabled input上的值设置为可交互的input上的值;
- 点击cancel后,可交互的 input上的值设置从disabled input上的值。
实现
- 如果用Reactive form, 则在
app.module.ts
的imports
array中加入ReactiveFormsModule
;如果用Template-driven form,则在imports
array中加入FormsModule
.
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule,
FormsModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- 写html页面
app.component.html
<div *ngIf="editMode">
name:
<input type="text" [formControl]="nameControl"/>
zodiac sign:
<input [formControl]="zodiacSignControl"/>
<div>
<button (click)="apply()">apply</button>
<button (click)="cancel()">cancel</button>
</div>
</div>
<div *ngIf="!editMode" (click)="onClick()">
name:
<input disabled [formControl]="showNameControl"/>
zodiac sign:
<input disabled [formControl]="showZodiacSignControl"/>
</div>
- 写逻辑
app.component.ts
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
editMode = false;
showNameControl = new FormControl('Tim');
showZodiacSignControl = new FormControl('Lion');
nameControl = new FormControl(this.showNameControl.value);
zodiacSignControl = new FormControl(this.showZodiacSignControl.value);
apply() {
this.editMode = false;
this.showNameControl.setValue(this.nameControl.value);
this.showZodiacSignControl.setValue(this.zodiacSignControl.value);
}
cancel() {
this.nameControl.setValue(this.showNameControl.value);
this.zodiacSignControl.setValue(this.showZodiacSignControl.value);
}
onClick() {
this.editMode = true;
}
}
常见错误
-
can't bind to 'ngModel' since it isn't a known property of 'input'
orcan't bind to 'formControl' since it isn't a known property of 'input'
- 可能忘记在
app.module.ts
的imports
array中加入相应的module
repo: https://github.com/LiuKaixinHappy/angular-form-demo
好的angular form博客: