angular reactive form
这篇文章讲了angular reactive form,
这里是angular file upload 组件 https://malcoded.com/posts/angular-file-upload-component-with-express/
原文:https://malcoded.com/posts/angular-fundamentals-reactive-forms/
------------------------------------
Forms are arguably one point where angular really shines.
So learning how forms work in angular is an essential skill.
In this tutorial we are going to take a close look at one of the two ways to create forms in angular. The reactive forms.
We will dive right into code and discover all the details about reactive forms in the angular framework step by step and with easy examples.
So, without further ado, let’s get started!

Forms in Angular
There are two different approaches to forms in Angular.
The first category are the template-driven forms. Using this method, you first create html-input-elements and then use directives like ngModel to bind their value to a component’s variable.
Personally, I’ve used this technique a lot. But that way only because I did not know about the other category.
Reactive Forms.
Reactive Forms a kind of the opposite to template-driven forms. Instead of defining the form in your template, the structure of the form is defined in code.
This maybe sounds a little bit odd now. At least I felt like this.
“Isn’t it twice the work, to define the form in code?”
“And isn’t it much harder to read?”
That was what I asked myself and that is what you should ask yourself, too!
But please wait with that, until you read this article and fully understand the topic.
To answer these questions, let’s dive right in and just build a small example using reactive forms together!

Importing the Module
For this example we are going to use a blank angular-cli application.
I you haven’t done so already, please go ahead and create one:
ng new [name]
As you probably know, Angular is organized in modules.
To use certain features, we first need to import the modules that contain that feature, before we can use it.
This is true for reactive forms, as well.
To use reactive forms, we need to import the ReactiveFormsModule into our parent module.
In our case, the parent module is the AppModule.
Let’s import the required module into it:
src/app.module.ts
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { ReactiveFormsModule } from '@angular/forms'
import { AppComponent } from './app.component'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent],
})
class AppModule {}

Defining a Model
In this example we are going to create a simple contact-form, because I couldn’t think of something more creative.
Before we start creating our form, we first need to define, which information we would like to gather with it.
To do so, we are creating a so called model.
A model is just a class, that contains all the fields, that our data can have.
All we need to do, is to create a new file for that class. Also, I typically create a new folder called models to contain all models of the application.
Inside of that file, we create our model. In this case, the data will be split in two parts.
Personal data about the person using the contact-form and the actual data he/she wants to submit.
The model for that looks like this:
src/models/contact-request.ts
export class ContactRequest {
personalData: PersonalData
requestType: any = ''
text: string = ''
}
class PersonalData {
email: string = ''
mobile: string = ''
country: string = ''
}
As you can see, I have also added default values to each field, as we will require them later.

Setting up a Contact-Component
Next, we need a component, to create our form in.
So let’s just create one!
Just use the following command of the angular-cli:
ng generate component contact
This will create a basic component for us to use. It will also import that component into our AppModule automatically.

Creating a Reactive Form in Angular
Now we can finally start creating our form.
Other than with template-driven forms, we can not simply use the model we have created earlier.
Instead we have to create a different one. One, that is only responsible for the form-representation.
But why doe we have to do that? Isn’t that much more complex that just binding to the model ?
Of course it is.
But binding to the model directly comes with one large downside.
We are altering the original data directly.
Reactive Programming and Immutability
This has become bad-practice in the last couple years, as a paradigm called reactive programming took the programming world over more and more.
Why?
Well, the simplest answer might be, that we loose the original data. If the user decides to abort his action, we can not recover the previous state, as we have overwritten it.
What we do with reactive forms instead, is keeping the data in the form model, until the user hits the submit button.
Only then the data is copied over to the original model, replacing everything. This type of overwriting everything is called “immutable objects”.
Form Controls
To create this form-model, angular uses a class called FormGroup.
To define our form-model, we create a new FormGroup. The constructor of this class then takes an object, that can contain sub-form-groups and FormControls.
FormControls represent the leafs in this tree. They are the smallest possible unit and typically represent a HTML-control (input, select, …) of your template.
In actuall code, let’s create a new method, that creates a new instance of the form-model for us. We call this mehtod: createFormGroup.
src/contact/contact.component.ts
createFormGroup() {
return new FormGroup({
personalData: new FormGroup({
email: new FormControl(),
mobile: new FormControl(),
country: new FormControl()
}),
requestType: new FormControl(),
text: new FormControl()
});
}
You will notice the similarities with our contact-request model.
In fact, I would recommend that you always keep them that similar. That way, you wont have any trouble converting the form-model to your actual model.
Because we want the country and the request Type to be select-able as a drop-down, we also have to provide some options to choose from:
src/contact/contact.component.ts
countries = ['USA', 'Germany', 'Italy', 'France'] requestTypes = ['Claim', 'Feedback', 'Help Request']
Finally, we save the result of that method to a public field, to be accessible in our template.
src/contact/contact.component.ts
contactForm: FormGroup;
constructor() {
this.contactForm = this.createFormGroup();
}
Here is how your component should look like now:
src/contact/contact.component.ts
import { Component, OnInit } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: ['./contact.component.css'],
})
class ContactComponent implements OnInit {
contactForm: FormGroup
countries = ['USA', 'Germany', 'Italy', 'France']
requestTypes = ['Claim', 'Feedback', 'Help Request']
constructor() {
this.contactForm = this.createFormGroup()
}
// Step 1
createFormGroup() {
return new FormGroup({
personalData: new FormGroup({
email: new FormControl(),
mobile: new FormControl(),
country: new FormControl(),
}),
requestType: new FormControl(),
text: new FormControl(),
})
}
ngOnInit() {}
}

Implementing the Template
For now that is all we need to do code-wise.
Let’s take a look how the counterpart, the template will look like.
Basically, our HTML does look just like a regular form. The only difference is, that we have to tell angular, which FormGroup and which FormControl to use for each control.
To see the result, I’ve also added a paragraph to print out our form-model as json.
src/contact/contact.component.html
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()" novalidate>
<div formGroupName="personalData" novalidate>
<input formControlName="email" /> <input formControlName="mobile" />
<select formControlName="country">
<option *ngFor="let country of countries" [value]="country"
>{{country}}</option
>
</select>
</div>
<select formControlName="requestType">
<option *ngFor="let requestType of requestTypes" [value]="requestType"
>{{requestType}}</option
>
</select>
<input formControlName="text" />
<button type="submit" [disabled]="contactForm.pristine">Save</button>
<button type="reset" (click)="revert()" [disabled]="contactForm.pristine">
Revert
</button>
</form>
At this point, your app should be in a runable state again.
In case you didn’t know: You can start your application using the
ng serve
command.

Using the Angular Form-Builder
From the example of our TypeScript code above, we can say that the code is starting to look cluttered already.
To solve that, angular provides a service called FormBuilder. This FormBuilder allows us to build our form-model with less code.
To use the FormBuilder, we need to request it via dependency injection. We do so in the constructor of our component.
src/contact/contact.component.ts
constructor(private formBuilder: FormBuilder) {
this.contactForm = this.createFormGroup();
}
The FormBuilder class has to be imported from @angular/forms:
src/contact/contact.component.ts
import { FormControl, FormGroup, FormBuilder } from '@angular/forms'
Now we can use that FromBuilder to build our form-model. For demonstration-purposes, I have created a new method called “createFormGroupWithBuilder”. You can just replace you previous code if you want to.
src/contact/contact.component.ts
createFormGroupWithBuilder(formBuilder: FormBuilder) {
return formBuilder.group({
personalData: formBuilder.group({
email: 'defaul@email.com',
mobile: '',
country: ''
}),
requestType: '',
text: ''
});
}
Using this approach, we have to define the default values of each field. You can just pass them an empty string, or fill it with some default-data as I did with the “email”-field.
Passing a Class to the Form-Builder
I turns out, using the FormBuilder, we can further optimize our code.
Instead of defining our form-model inline, the FormBuilder allows us to pass in any JavaScript object.
So we can just pass in a new instance of our PersonalData class.
src/contact/contact.component.ts
createFormGroupWithBuilderAndModel(formBuilder: FormBuilder) {
return formBuilder.group({
personalData: formBuilder.group(new PersonalData()),
requestType: '',
text: ''
});
}
However, we have to make sure, that all fields of the form are also present in this object. This is why we have assigned the default values in our contact-request-model.

Extracting the Data from the Form
Now that have talked about our more than enough, it’s time to worry about getting our data out of that form into an contact-request object.
For that, we are using the submit-button, we have created earlier in our template. We also already registered the callback-method “onSubmit”.
To be able to listen to the button-press, we need to implement that callback in our component.
Inside of that callback, we can access the form’s values by its values property.
this.contactForm.value
But we need to be careful here. These values are still referenced by our form. If we just copy that reference and modify the data elsewhere, the form will be impacted, as well. This can cause weird side-effects.
This is why we need to create a copy of the data. In this example we are using Object.assign for that.
const result: ContactRequest = Object.assign({}, this.contactForm.value);
However, that is not enough. Object.assign creates something called a shallow copy. That means that all primary-fields of the object are copied properly, but the references to sub-objects or lists are still the same. Not noticing this problem does cause even more weird side-effects.
Instead what we want to do is create a deep copy. We can either achieve that by doing it copying everything manually or use a utility like lodash’s cloneDeep function. We will use the manual method here.
result.personalData = Object.assign({}, result.personalData);
Overall, the onSubmit method should now look something like this:
src/contact/contact.component.ts
onSubmit() {
// Make sure to create a deep copy of the form-model
const result: ContactRequest = Object.assign({}, this.contactForm.value);
result.personalData = Object.assign({}, result.personalData);
// Do useful stuff with the gathered data
console.log(result);
}

Resetting the Form
Resetting the form is definitely one of the easier parts with reactive forms.
Again, we are going to use the reset-button, we have included into our template already.
All we need to do now, is to implement the revert-callback into our component.
To reset the form, we can either use the form’s reset method without any parameter,
// Resets to blank object
this.contactForm.reset();
which results in an empty object, or pass a set of default parameters along:
// Resets to provided model
this.contactForm.reset({ personalData: new PersonalData(), requestType: '', text: '' });
All in all the revert method simply looks like this:
src/contact/contact.component.ts
revert() {
// Resets to blank object
this.contactForm.reset();
// Resets to provided model
this.contactForm.reset({ personalData: new PersonalData(), requestType: '', text: '' });
}
Conclusion
In this tutorial we learned how to create forms with angular using the reactive-forms method.
I hope you enjoyed this post.
If you did please hit the share button below and help other people understand reactive-forms in angular, as well.
Have a fantastic day!
angular reactive form的更多相关文章
- [Angular] Reactive Form -- FormControl & formControlName, FormGroup, formGroup & formGroupName
First time dealing with Reactive form might be a little bit hard to understand. I have used Angular- ...
- Angular Reactive Form - 填充表单模型
setValue 使用setValue,可以通过传递其属性与FormGroup后面的表单模型完全匹配的数据对象来一次分配每个表单控件值. 在分配任何表单控件值之前,setValue方法会彻底检查数据对 ...
- Angular:Reactive Form的使用方法和自定义验证器
本文将介绍Angular(Angular2+)中Reactive Form的有关内容,包括: Reactive Form创建方法 如何使用验证 自定义验证器 下面开始进入正文! Reactive Fo ...
- [Angular2 Form] Reactive form: valueChanges, update data model only when form is valid
For each formBuild, formControl, formGroup they all have 'valueChanges' prop, which is an Observable ...
- Angular Reactive Forms -- Model-Driven Forms响应式表单
Angular 4.x 中有两种表单: Template-Driven Forms - 模板驱动式表单 (类似于 AngularJS 1.x 中的表单 ) 官方文档:https://v2.angul ...
- angular.js form
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- [Angular2 Form] Create and Submit an Angular 2 Form using ngForm
Forms in Angular 2 are essentially wrappers around inputs that group the input values together into ...
- angular实现form验证
先上效果页面:https://lpdong.github.io/myForm-1/ 其中几个知识点 1.angularJs提供了几个新的type类型: type="password" ...
- Angular Reactive Form-响应式表单验证
内建验证规则 Angular中提供了一些內建的Validators,这些验证规则可以在Template-Driven或Reactive表单中使用. 目前 Angular 支持的内建 validator ...
随机推荐
- 35.百度云语音识别接口使用及PyAudio语音识别模块安装
百度云语音识别接口使用: 百度云语音识别接口文档:https://cloud.baidu.com/doc/SPEECH/ASR-API.html#JSON.E6.96.B9.E5.BC.8F.E4.B ...
- luogu P1734 最大约数和 (01 背包)
链接:https://www.luogu.org/problemnew/show/P1734 题面: 题目描述 选取和不超过S的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大. 输入输出格 ...
- IDEA操作之test case coverage的方法
作用: 用于自动化测试,检查单元测试的覆盖率情况. 安装: 1.点击 Run * with coverage 或者右键已经定义为test source的package选择(单个test class同 ...
- Kubernetes---容器探针
⒈含义 探针是由各个节点的kubelet对容器执行的定期诊断.要执行诊断,kubelet 调用由容器实现的Handler[处理程序].有三种类型的处理程序: >ExecAction:在容器内执行 ...
- 在win下开发的项目怎么迁移到linux下面才能正常运行?
我可以直接拷贝项目目录到linux下面直接操作吗? 答案: 可以,咋可能??? 为啥??? win开发直接拷贝过去,你不凉谁凉了,我以前也同样的单纯,如果你项目里用的绝对路径! 那恭喜你,你凉了,清楚 ...
- Reids 连环炮面试(转)
出处: <今天面试了吗>-Redis Redis是什么 面试官:你先来说下redis是什么吧 我:(这不就是总结下redis的定义和特点嘛)Redis是C语言开发的一个开源的(遵从BSD ...
- 在windows部署service
首先,需要在环境变量的path中加入Install Util的路径: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 注意这里的Framework\v2.0 ...
- c++容易混淆知识点
C ++令人困惑的知识点1 函数传递指针和传递引用之间的区别? 1 GT;指针定义可能未初始化,但引用不可能; 2 - ;引用只能与一个实体组合,指针可以与多个实体组合; 3 GT;加法和减法的含义是 ...
- Java学习路径(抛光砖)
这就是我刚刚在五孔问答中找到的Java学习路线图抛光砖价格.我个人认为,这条Java学习路线是可以的.它是2018年相对较新的Java学习路线,更符合企业就业标准. Java学习路径的第一阶段:Jav ...
- JAVA栅栏和闭锁的区别
闭锁:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.即,一组线程等待某一事件发生,事件没有发生前,所有线程将阻塞等待:而事件发生后,所有线程将开始执行:闭锁最初 ...