简介:我用的ionic开发,表单用的响应式开发,包括动态表单、字段验证等。
服务引入
我用的版本是ionic4,这里的引入跟 app.module.ts 没有半毛钱关系,引入的是对应page页面的 module.ts
import {ReactiveFormsModule} from "@angular/forms";
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild(routes),
ReactiveFormsModule
],
declarations: [ReceiptgoodsPage]
})
表单定义+响应式表单
import { FormControl, FormGroup, Validators, FormBuilder, FormArray } from "@angular/forms";
import { telphone, idcard, carnumber, integer, positivefloat, numbercompare } from '../services/regrepress';
constructor(
private fb: FormBuilder,
){}
//表单
groupForm = this.fb.group({
ID: [''],//发货单号
BH: ['', [Validators.required]],//发货单号
//司机信息
CPH: ['', [Validators.required, carnumber]],//车牌号
SFPZ_SJXM: ['', [Validators.required, Validators.maxLength(10)]],//司机姓名
SJSFZ: ['', [Validators.required, idcard]],//司机身份证
SJSJH: ['', [Validators.required, telphone]],//司机电话
//收料人信息
SLR: [''],//收料人
SLRDH: [''],//收料人电话
SLDZ: [''],//收料地址
Arr: this.fb.array([]), // 收料明细
});
注意看这里的 Arr,因为是从后台获取的数据,所以在获取的数据的那里动态创建
const arr = this.groupForm.get('Arr') as FormArray;
result.forEach(item => {
arr.push(
this.fb.group({
WZID: [item.SFPZMX_WZID],
// SFPZ_BH: [item.SFPZMX_WZBH],
WZBH: [item.SFPZMX_WZBH],
WZMC: [item.SFPZMX_WZMC],
GGXH: [item.SFPZMX_GGXH],
JLMC: [item.SFPZMX_JLMC],
YFSL: [item.SFPZMX_YFSL],
SYSL: [item.SFPZMX_SYSL],
SFSL: [item.SFPZMX_SFSL ? item.SFPZMX_SFSL : '', [Validators.required, integer, numbercompare]],
DJ: [item.SFPZMX_DJ],
})
)
});
这样 就有动态的字段
前台以及 验证
<ion-item class="titletop" lines="none">
<ion-label class="mustwrite">司机手机号</ion-label>
<ion-input placeholder="请输入" formControlName="SJSJH"></ion-input>
</ion-item>
<div *ngIf="groupForm.get('SJSJH').invalid && (groupForm.get('SJSJH').dirty || groupForm.get('SJSJH').touched)"
class="alert alert-danger">
<div *ngIf="groupForm.get('SJSJH').errors.required">司机手机号不能为空</div>
<div *ngIf="groupForm.get('SJSJH').errors.telphone">请输入正确的手机号</div>
</div>
<div formArrayName="Arr">
<div *ngFor="let item of groupForm.controls['Arr'].controls;
let i = index;">
<div [formGroupName]="i">
<ion-item-divider>
<ion-label>
订货明细{{i+1}}
</ion-label>
</ion-item-divider>
<!-- 物资编号 -->
<ion-item class="titletop" lines="none">
<ion-label>物资编号</ion-label>
<ion-input formControlName="WZBH" readonly></ion-input>
</ion-item>
<!-- 物资名称 -->
<ion-item class="titletop" lines="none">
<ion-label>物资名称</ion-label>
<ion-input formControlName="WZMC" readonly></ion-input>
</ion-item>
<!-- 规格型号 -->
<ion-item class="titletop" lines="none">
<ion-label>规格型号</ion-label>
<ion-input formControlName="GGXH" readonly></ion-input>
</ion-item>
<!-- 单位 -->
<ion-item class="titletop" lines="none">
<ion-label>计量单位</ion-label>
<ion-input formControlName="JLMC" readonly></ion-input>
</ion-item>
<ion-item class="titletop" lines="none">
<ion-label>单价</ion-label>
<ion-input formControlName="DJ" readonly></ion-input>
</ion-item>
<ion-item class="titletop" lines="none">
<ion-label>预发数量</ion-label>
<ion-input formControlName="YFSL" readonly></ion-input>
</ion-item>
<ion-item class="titletop" lines="none">
<ion-label>剩余数量</ion-label>
<ion-input formControlName="SYSL" readonly></ion-input>
</ion-item>
<ion-item class="titletop" lines="none">
<ion-label [ngClass]="{'mustwrite': type=='noSend'}">实发数量</ion-label>
<ion-input formControlName="SFSL" [readonly]="type=='hasSend'"></ion-input>
</ion-item>
<div
*ngIf="groupForm.get('Arr').controls[i].invalid && (groupForm.get('Arr').controls[i].get('SFSL').dirty || groupForm.get('Arr').controls[i].get('SFSL').touched)"
class="alert alert-danger">
<div *ngIf="groupForm.get('Arr').controls[i].get('SFSL').errors.required">实发数量不能为空</div>
<div *ngIf="groupForm.get('Arr').controls[i].get('SFSL').errors.integer">请输入数字</div>
<div *ngIf="groupForm.get('Arr').controls[i].get('SFSL').errors.crosssysl">实发数量不能超过剩余数量</div>
<div *ngIf="groupForm.get('Arr').controls[i].get('SFSL').errors.corssyfsl">实发数量不能超过预发数量</div>
</div>
</div>
</div>
</div>
验证的方法
import { AbstractControl, FormControl } from "@angular/forms";
//control是我们要验证的表单控件,
export function beginWith(control: AbstractControl) {
const result = /^13/.test(control.value);
return result ? null : { 'beginWith': { value: control.value } };
}
//手机号
export function telphone(control: AbstractControl) {
// debugger;
const result = /0?(13|14|15|18|17)[0-9]{9}/.test(control.value);
return result ? null : { 'telphone': { value: control.value } };
}
//身份证
export function idcard(control: AbstractControl) {
// debugger;
const result = /\d{17}[\d|x]|\d{15}}/.test(control.value);
return result ? null : { 'idcard': { value: control.value } };
}
//正浮点数
export function positivefloat(control: AbstractControl) {
// debugger;
const result = /[1-9]\d*/.test(control.value);
return result ? null : { 'integer': { value: control.value } };
}
//正整数
export function integer(control: AbstractControl) {
// debugger;
const result = /[1-9]\d*/.test(control.value);
return result ? null : { 'integer': { value: control.value } };
}
//车牌号
export function carnumber(control: AbstractControl) {
// debugger;
const result = /(^[\u4E00-\u9FA5]{1}[A-Z0-9]{6}$)|(^[A-Z]{2}[A-Z0-9]{2}[A-Z0-9\u4E00-\u9FA5]{1}[A-Z0-9]{4}$)|(^[\u4E00-\u9FA5]{1}[A-Z0-9]{5}[挂学警军港澳]{1}$)|(^[A-Z]{2}[0-9]{5}$)|(^(08|38){1}[A-Z0-9]{4}[A-Z0-9挂学警军港澳]{1}$)/.test(control.value);
return result ? null : { 'carnumber': { value: control.value } };
}
//实发 与剩余数量 预发数量 比较
export function numbercompare(control: AbstractControl) {
if (!control.parent) {
return true;
}
var result = true;
// debugger;
//预发数量
var YFSL = parseInt(control.parent.value.YFSL);
//剩余数量
var SYSL = parseInt(control.parent.value.SYSL);
//实发数量
var SFSL = parseInt(control.value);
if (SYSL) {
SFSL > SYSL ? result = false : result = true;
return result ? null : { 'crosssysl': { value: control.value } };
} else {
SFSL > YFSL ? result = false : result = true;
return result ? null : { 'corssyfsl': { value: control.value } };
}
}