angular2表单最常用的方法就是在input或者textarea里直接添加formControlName或者formGroupName进行数据双向绑定并验证。
1 <form [formGroup]="goodsFormInfo">
2 <input type="text" formControlName="book_file" readonly="" />
3 <!--或者-->
4 <dl formGroupName="book_isbn">
5 <dt>
6 <span>*</span>ISBN号:
7 </dt>
8 <dd>
9 <input id="book_isbn1" td-focus="" formControlName="book_isbn1" [patterninput]="'^[0-9]+$'" class="isbn" type="text" maxlength="3" />
10 <span>-</span>
11 <input id="book_isbn2" td-focus="" formControlName="book_isbn2" [patterninput]="'^[0-9]+$'" class="isbn" type="text" maxlength="1" />
12 <span>-</span>
13 <input id="book_isbn3" td-focus="" formControlName="book_isbn3" [patterninput]="'^[0-9]+$'" class="isbn" type="text" maxlength="7" />
14 <span>-</span>
15 <input id="book_isbn4" td-focus="" formControlName="book_isbn4" [patterninput]="'^[0-9]+$'" class="isbn" type="text" maxlength="6" />
16 <span>-</span>
17 <input id="book_isbn5" td-focus="" formControlName="book_isbn5" [patterninput]="'^[0-9]+$'" class="isbn" type="text" maxlength="1" />
18 <p class="warn-mark" *ngIf="mesg('book_isbn1') || mesg('book_isbn2') || mesg('book_isbn3') || mesg('book_isbn4') || mesg('book_isbn5') || mesg('book_isbn')"> {{ mesg('book_isbn1') || mesg('book_isbn2') || mesg('book_isbn3') || mesg('book_isbn4') || mesg('book_isbn5') || mesg('book_isbn') }}</p>
19 </dd>
20 </dl>
21 </form>
不过最近遇到一个比较复杂的表单提交, 如果全部写在一个组件里,代码可读性太差,所以把表单拆成了多个组件,通过formControlName进行数据的双向绑定。
举个简单的例子(核心代码):
一、form表单-html代码
1 <dl>
2 <dt> 商品定时下架:</dt>
3 <dd>
4 <tl-goods-sold-out-timing formControlName="auto_off_date"></tl-goods-sold-out-timing>
5 <p class="color-grey">系统会在该时间自动执行下架</p>
6 <p class="warn-mark warn-date" *ngIf="mesg('auto_off_date')">{{mesg('auto_off_date')}}</p>
7 </dd>
8 </dl>
9 <button class="btn btn-blue" (click)="submit()">保存</button>
二、tl-goods-sold-out-timing子组件 - html代码
1 <div class="clearfix">
2 <tl-check-box [labelname]="'设定'" [(ngmodel)]="isChecking" (onselectedfn)="selectedFn($event)"></tl-check-box>
3 <div class="position-relative">
4 <tl-calendar [calendarobj]="calendarObj" [(ngModel)]="startDate" (ngModelChange)="selectDate($event)"></tl-calendar>
5 </div>
6 </div>
看到这里一定很奇怪,为什么同时写了ngModel和ngModelChange,ngModelChange在ts文件里会用到,这个日历组件的值改变后会需要我们调用一个change事件的,往下看。
三、tl-goods-sold-out-timing子组件 - ts代码
import { Component, OnInit, Output, Input, EventEmitter, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CalendarObj } from '../../../../../shared'
@Component({
selector: 'tl-goods-sold-out-timing',
templateUrl: './goods-sold-out-timing.component.html',
styleUrls: ['./goods-sold-out-timing.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GoodsSoldOutTimingComponent),
multi: true
}
]
})
export class GoodsSoldOutTimingComponent implements OnInit {
public calendarObj: CalendarObj;
public isChecking: boolean;
public startDate: Date;
private change = (value) => { }; // 划重点
constructor() {
this.calendarInit();
}
ngOnInit() { }
get auto_off_date() { // 父组件的formControlName接收这块return的数据 get的auto_off_date名称和下面this.change(this.auto_off_date);括号中的值名称一样
console.log(this.startDate);
if (!this.isChecking) {
return {
date: '',
set: this.isChecking
}
}
return {
date: this.startDate ? this.formatDate(this.startDate) : '',
set: this.isChecking
}
}
registerOnChange(fn) {
this.change = fn;
}
registerOnTouched(fn) { }
writeValue(value) { // 初始时如果父组件有值传入,就从这里写入组件。
console.log(value);
if (!value) {
this.isChecking = false;
} else {
this.startDate = new Date(value.substr(0, 10)); // startDate为日历组件数据de双向绑定
this.isChecking = true;
console.log(this.startDate);
}
}
// check-box事件
selectedFn(event) {
this.change(this.auto_off_date);
}
// 日期改变
selectDate(date) { // 数据一但改变,就调用一次change事件,如果上面html文件中没有写ngModelChange,这里日期改变就无法传值给父组件
console.log(date);
this.startDate = date;
this.change(this.auto_off_date);
}
// 日期格式转化
formatDate = function (date) {
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? '0' + m : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
return y + '-' + m + '-' + d;
};
// 日历组件初始化
calendarInit() {
this.calendarObj = new CalendarObj();
this.calendarObj.placeholder = '开始日期';
this.calendarObj.readonly = true;
this.calendarObj.yearNavigator = true;
this.calendarObj.monthNavigator = true;
this.calendarObj.showOtherMonths = true;
this.calendarObj.style = { 'width': '93px' };
this.calendarObj.inputStyle = { 'width': '93px', 'background-position': '87px 1px', 'border': '1px solid #c7c7c7' };
}
}
四、form表单-ts代码
formControlName="auto_off_date"接收到数据后,我们需要验证一下数据。
submit(){
console.log(this.goodsFormInfo.value); // 打印表单接收到的数据
if(this.goodsFormInfo.valid){
// 如果通过验证就提交
}
}
// 表单验证
formInfoInit() {
this.goodsFormInfo= this.fb.group({
'auto_off_date': ['', [this.validDate()]],
})
}
mesg(field: string) {
return this.formUtil.mesg(field);
}
// 错误提示
private validMessages = {
'auto_off_date': { 'dateError': '请选择定时下架时间' },
};
// 验证 - 定时下架
reqDate() {
return ((control) => {
console.log(control);
if (control.value && control.value.set) {
if (control.value.date == '') {
return { dateError: false };
} }
});
}
(本文原创,转载请注明出处!!)