正常使用
formControl与验证器的正常使用:
<!-- formGroup -->
<form [formGroup]="editForm">
<mat-form-field>
<mat-label>名称</mat-label>
<input [type]="'text'" formControlName='name' matInput required>
<mat-error *ngIf="editForm.get('name').invalid&&(editForm.get('name').dirty||editForm.get('name').touched)">
<span *ngIf="editForm.get(['name']).hasError('required')">该字段必填</span>
</mat-error>
</mat-form-field>
</form>
<!-- formControl -->
<mat-form-field>
<mat-label>名称</mat-label>
<input [type]="'text'" [formControl]='name' matInput required>
<mat-error *ngIf="name.invalid&&(name.dirty||name.touched)">
<span *ngIf="name.hasError('required')">该字段必填</span>
</mat-error>
</mat-form-field>
import {FormBuilder, Validators} from "@angular/forms";
export class AppComponent{
// 使用formGroup
editForm=this.fb.group({
name:[null,[Validators.required]]
})
// 或者使用formControl
name=this.fb.control(null,[Validators.required])
constructor(
private fb: FormBuilder,
) {
}
}
特殊需求与问题
问题1. 经观察发现,当且仅当用户点击页面输入框时,才触发表单控件的验证,如何不进行操作,立即触发表单验证?
// html文件不改动
import { OnInit } from '@angular/core';
import {FormBuilder, Validators} from "@angular/forms";
export class AppComponent implements OnInit{
// 使用formGroup
editForm=this.fb.group({
name:[null,[Validators.required]]
})
// 或者使用formControl
name=this.fb.control(null,[Validators.required])
constructor(
private fb: FormBuilder,
) {
}
ngOnInit(): void {
// 使用formGroup
const formControl=this.editForm.get('name')
formControl.markAsTouched();
formControl.updateValueAndValidity();
// 或者使用formControl
this.name.markAsTouched();
this.name.updateValueAndValidity();
}
}
问题2. 现有一需求,涉及自封装组件、模板、不定长数组、表单验证影响按钮等功能,其具体页面如下:
如何搭建页面满足该需求?
下面将给出一种解决方案:
在list的数据量较大,且item个数具有不确定性的情况下,考虑到前端页面性能,一般不考虑通过formBuilder创建一个formArray与HTML元素进行绑定,这时就需要引入一个新的概念——采用模板驱动表单的方式解决该复杂问题。
什么是模板驱动表单?将通过下面的代码进行简要说明
<!-- 单个表单验证器 -->
<input type="text" name="fieldOne" [ngModel]="fieldOne">
<input type="text" name="fieldTwo" ngModel>
<!-- 整个表单-->
<form #form="ngForm">
<input type="text" name="firstField" [ngModel]="model.firstField">
</form>
@Component({
selector: 'app-reactive',
})
export class myComponent {
fieldOne='';
model = {
firstField: ''
};
}
由代码可以看出,表单元素绑定的是普通的js变量而非一般的formControl,为区分各表单元素,必须给每个元素进行命名,并且在ngModel无绑定变量的时候仍需指明ngModel,更为详细的介绍可以参阅一位前辈的这篇文章:https://blog.youkuaiyun.com/Herishwater/article/details/105635514
回到正题,上文中我们提到的这种较为复杂的需求,我们该如何解决?下面是一种简要的解决方法:
<div>
<button [disable]="myForm.invalid"></button>
<form #myForm="ngForm">
<my-list-component [data]="myList" [itemTemplateRef]='myTemplateRef'></my-list-component>
<ng-template #myTemplateRef let-item let-index="index">
<input name='field{{index}}'
#field="ngModel"
[(ngModel)]='item.field'
type='text'
required>
<div *ngIf="field.invalid">field is required</div>
</ng-template>
</form>
</div>
<!-- 注意,即使是ng-template,也要被包含于form中,ngForm才能关联到input对应的ngModel-->
@Component({
selector: 'app-reactive',
})
export class myComponent {
myList=[
{field:null},
{field:null},
{field:null},
{field:null},
{field:null},
]
}
其中自封装组件代码也简要给出
<!-- my-list-component -->
<div class="list">
<div *ngFor="let item of data;let i = index" class="list-item">
<ng-container *ngTemplateOutlet="itemTemplateRef context: {$implicit: item,index:i}"></ng-container>
</div>
</div>
import { Component,Input, TemplateRef } from '@angular/core';
@Component({
selector: 'my-list-component',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnChanges {
@Input()
itemTemplateRef: TemplateRef<any>;
@Input()
data: any[] = []
}
至此,又一问题得到解决。
后续问题,等待更新…