Angular动态表单常规设计(一)
由浅入深理解动态表单的一般使用
当表单结构类似,频繁地使用响应式表单或许是一件增加工作量地事情,除了将模板进行合理地封装,表单模型也要能够灵活地构造,此时推荐使用动态表单。
先理解再优化
动态表单模板中,value、label均动态化,表单字段也是动态绑定,比较基础地模型是一个数组循环与模板绑定处理;生成一个formGroup,会根据不同地类型区分,此时不包含重复项。数据模型数据:
this.base = [
{
key: 'userName',
label: '姓名',
value: null,
validators: [Validators.required]
},
{
key: 'age',
label: '年龄',
value: null,
validators: [Validators.required]
}
];
form生成:
this.form = this.toFormGroup(this.base);
toFormGroup(options: any[]) {
const group = {};
options.forEach(item => {
group[item.key] = new FormControl(item.value, item.validators);
});
return new FormGroup(group);
}
模板
<form nz-form [formGroup]="form" (ngSubmit)="submit(form)">
<div *ngFor="let item of base">
<ng-container [formGroup]="form">
<div nz-row nzFlex [nzGutter]="8">
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label [nzSpan]="10">{{item.label}}</nz-form-label>
<nz-form-control [nzSpan]="14">
<input nz-input type="text" [formControlName]="item.key" placeholder="Enter Your Working date..." />
</nz-form-control>
</nz-form-item>
</div>
</div>
</ng-container>
</div>
</form>
优化
模板组件化,方法服务化basic-form
<form nz-form [formGroup]="form" (ngSubmit)="submit(form)">
<ng-container [formGroup]="form">
<div nz-row nzFlex [nzGutter]="8">
<div nz-col [nzSpan]="6" *ngFor="let item of base">
<nz-form-item>
<nz-form-label [nzSpan]="10">{{item.label}}</nz-form-label>
<nz-form-control [nzSpan]="14">
<input nz-input type="text" [formControlName]="item.key" placeholder="{{item.placeholder}}" />
</nz-form-control>
</nz-form-item>
</div>
</div>
</ng-container>
</form>
我们需要实现一个根据不同学龄阶段的学生生成不同的某个申请表单,这时表单需要动态化处理,
修改代码:
view.component.html
<div nz-row nzGutter="16">
<div nz-col nzSpan="24">
<nz-radio-group [(ngModel)]="grade" (ngModelChange)="gradeChange($event)">
<label nz-radio-button nzValue="junior"><span>小学</span></label>
<label nz-radio-button nzValue="middle"><span>初中</span></label>
<label nz-radio-button nzValue="high"><span>高中</span></label>
</nz-radio-group>
</div>
</div>
<section class="form-container">
<basic-form [form]="form" [data]="formData"></basic-form>
</section>
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormArray, FormControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { FormService } from '../share/form.service';
interface FormFieldObject {
key: string;
label: string;
value: any;
placeholder: string;
validators: ValidatorFn[];
}
@Component({
selector: 'app-view',
templateUrl: './view.component.html',
styleUrls: ['./view.component.scss']
})
export class ViewComponent implements OnInit, AfterViewInit {
constructor(
private formService: FormService
) { }
form: FormGroup;
formData: FormFieldObject[];
base: FormFieldObject[];
grade = 'junior';
ngOnInit() {
this.base = [
{
key: 'userName',
label: '姓名',
value: null,
placeholder: 'Enter Your Name',
validators: [Validators.required]
},
{
key: 'age',
label: '年龄',
value: null,
placeholder: 'Enter Your Age',
validators: [Validators.required]
}
];
this.formData = [...this.base];
this.form = this.formService.createForm(this.formData);
}
gradeChange(event) {
this.base = [
{
key: 'userName',
label: '姓名',
value: null,
placeholder: 'Enter Your Name',
validators: [Validators.required]
},
{
key: 'age',
label: '年龄',
value: null,
placeholder: 'Enter Your Age',
validators: [Validators.required]
}
];
if (event === 'middle') {
const pre = [
{
key: 'junior',
label: '小学教育',
value: null,
placeholder: 'Enter Your junior school',
validators: [Validators.required]
}
];
this.formData = [...this.base, ...pre];
this.form = this.formService.createForm(this.formData);
} else if (event === 'junior') {
this.formData = [...this.base];
this.form = this.formService.createForm(this.formData);
} else {
const pre = [
{
key: 'junior',
label: '小学教育',
value: null,
placeholder: 'Enter Your junior school',
validators: [Validators.required]
},
{
key: 'middle',
label: '初中教育',
value: null,
placeholder: 'Enter Your middle school',
validators: [Validators.required]
}
];
this.formData = [...this.base, ...pre];
this.form = this.formService.createForm(this.formData);
}
}
ngAfterViewInit() {
}
}
import { Injectable } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
@Injectable({
providedIn: 'root'
})
export class FormService {
constructor() { }
createForm(arrays: any[]) {
const group = {};
arrays.forEach(item => {
group[item.key] = new FormControl(item.value, item.validators);
});
return new FormGroup(group);
}
}
模板组件
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
// tslint:disable-next-line: component-selector
selector: 'basic-form',
templateUrl: './basic-form.component.html',
styleUrls: ['./basic-form.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BasicFormComponent implements OnInit {
@Input() form: FormGroup;
@Input() data: any[];
constructor() { }
ngOnInit() {
}
submit() {
console.log(this.form.valid);
}
}
将表单控件的value、字段、placeholder文本,以及简单的验证器均动态化,保证了多条件下均可以提交和验证表单。
前端成长之踩坑经验
前端在开发中扮演者什么样得角色?可有可无?无足轻重?花里胡哨?应该是杂乱有章
推荐阅读
Angular8表单内置API窥探
目前表单是响应式类型,默认change状态进行校验,且初始值均为 空值(推荐使用null替代'')现在需求有所变动,申请单默认团建费用初始值设为1001,但是公司今年效益不是很好,要求团建费用不得大于1000.
何弃疗赞 2阅读 2.1k
Async Pipe 以及Promise
前言之前在写项目的时候引用某个管道的时候 <td>{{ house | housePlace }}发现效果不是想要的, 而是如下图的效果,并没有显示出正确的地址!参考项目中的代码发现需要加上async管道 <td>{{ house | h...
weiewiyi赞 2阅读 872
利用tethys在C层调用子组件弹窗
本周正式接手了新项目,目前感觉主要难度就体现在——找不到代码,找不到对应接口,项目主体结构与之前接触过的有较大差距。还有就是由于这个项目并不是只由我们来写,并且是最新的版本,所以这就不可避免的会遇到...
李明赞 3阅读 355
2023 重学 Angular
作者:徐海峰就在前几天(2022-11-07) Angular 正式发布了 v15 版本,本人第一时间用我那不专业的英文翻译了一下 [[译] Angular 15 正式发布!]([链接]) 文章一出就遭到社区部分人的质疑,什么 "Angular 落寞很...
PingCode研发中心赞 2阅读 483
angular 页面缩放时调整css
问题背景登录界面:由于之前登录框设置的是绝对位置,所以在浏览器页面缩小后,登录框的位置会缩到看不见的地方。比如left字段,设置的是370px。 当页面宽度缩小至400左右时,登录框就会由于向右偏移了370px,而导...
weiewiyi赞 2阅读 477
剪切板
写项目的时候需要用到剪切板的功能, 参考项目里的写法,用到了document.execCommand()方法。 {代码...} 看webstrom提示发现,这个方法是弃用的符号。 之后就想着看看现在用什么来代替。查看官方文档MD5官方文...
weiewiyi赞 2阅读 336
Service Worker 在 PWA 中的应用
在 Samsung Internet 中,有一个称为 ambient badging 的功能。 如果浏览器检测到该页面是 PWA,它会动态更新 URL 栏中常用的书签图标,将其更新为特殊的 + 图标,为用户提供一个简单的快捷方式将其添加到他们的...
JerryWang_汪子熙阅读 774
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。