将对下图所示的表单进行数据模型的创建和数据模板的绑定
【1】数据模型的创建
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Stock, StockService } from '../../stock.service';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
@Component({
selector: 'app-stock-form',
templateUrl: './stock-form.component.html',
styleUrls: ['./stock-form.component.css']
})
export class StockFormComponent implements OnInit {
public stock:Stock;
constructor(private routerinfo:ActivatedRoute,private stockService:StockService,private router:Router) { }
//创建表单模型对象,让angular来接管表单处理
private formModel:FormGroup; //并且要将当前这个属性绑定到模板中form标签的[formGroup]指令上
private categories=["IT","互聯網",'金融']; //股票类型初始化,原始数据,并将其绑定到模板
ngOnInit() {
let stockid=this.routerinfo.snapshot.params["id"];
if(stockid!=0){
this.stock=this.stockService.getStock(stockid);
}else{
this.stock=new Stock(0,"",0,0,"",[]);
}
//声明数据结构
let fb=new FormBuilder();
this.formModel=fb.group({
name:[this.stock.name,[Validators.required,Validators.minLength(3)]],
//将name绑定到模板页面的formControlName上:formControlName="name"
price:[this.stock.price,Validators.required],
desc:[this.stock.desc],
categories:fb.array([ //用法原因:股票的类型在定义的时候就是string的数组Array<string>,[true,true,null]
//this.stock.categories.indexOf(this.categories[0])!=-1 this.stock.categories里面有IT就返回true
new FormControl(this.stock.categories.indexOf(this.categories[0])!=-1),
new FormControl(this.stock.categories.indexOf(this.categories[1])!=-1),
new FormControl(this.stock.categories.indexOf(this.categories[2])!=-1),
])
});
}
save(){
//1.rating的处理,
this.formModel.value.rating=this.stock.rating;
//2 将股票类型转换为汉字
var categoriesChainese=[];
var index=0;
for(var i=0;i<3;i++){
if(this.formModel.value.categories[i]){ //说明当前项被选中,就将其转为汉字
categoriesChainese[index++]=this.categories[i]
}
}
this.formModel.value.categories=categoriesChainese;
//打印出表单数据模型
console.log(this.formModel.value);
//this.router.navigate(['/stock']);
}
}
【2】模板数据绑定
<p>
{{stock.name}}
</p>
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">股票信息</h3>
</div>
<!-- /.box-header -->
<!-- form start 首先用[formGroup]指令绑定后台声明的表单模型对象formModel -->
<form class="form-horizontal" [formGroup]="formModel">
<div class="box-body">
<div class="form-group">
<label for="name" class="col-sm-2 control-label">股票名称</label>
<div class="col-sm-10">
<!--将单个表单绑定到后台数据模型中定义的字段上 使用formControlName="name" -->
<input type="text" class="form-control" formControlName="name" id="name" placeholder="股票名称" >
</div>
</div>
<div class="form-group">
<label for="price" class="col-sm-2 control-label" >股票价格</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="price" formControlName="price" placeholder="股票价格">
</div>
</div>
<div class="form-group">
<label for="price" class="col-sm-2 control-label">股票评级</label>
<div class="col-sm-10">
<app-stars [(rating)]="stock.rating"></app-stars>
</div>
</div>
<div class="form-group">
<label for="price" class="col-sm-2 control-label" >股票描述</label>
<div class="col-sm-10">
<textarea class="form-control" formControlName="desc" placeholder="股票描述"></textarea>
</div>
</div>
<!-- 【1】将整个checkbox组绑定到后台的categories -->
<div class="form-group" formArrayName="categories">
<label for="categories" class="col-sm-2 control-label" >股票类型</label>
<!-- 【2】循环初始化数组categories -->
<div *ngFor="let category of categories;let i=index;" class=" col-sm-2">
<div class="checkbox ">
<label>
<!-- 【3】将每个checkbox绑定到categories的每个项,因为是绑定到变量上所以加[formControlName] -->
<input [formControlName]='i' type="checkbox" > {{category}}
</label>
</div>
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-default">取消</button>
<button type="submit" class="btn btn-info pull-right" (click)="save()" >保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->
【3】对表单模型添加校验规则,
##1 定义校验器
//股票类型校验器
categoriesSelectValidator(control:FormArray):any{
//
var valid=false;
control.controls.forEach(control=>{
if(control.value){
valid=true
}
});
if(valid){
return null;
}else{
return {categoriesLength:true};
}
}
##2 模型中使用校验器
//声明数据结构
let fb=new FormBuilder();
this.formModel=fb.group({
name:[this.stock.name,[Validators.required,Validators.minLength(3)]],
//将name绑定到模板页面的formControlName上:formControlName="name"
price:[this.stock.price,Validators.required],
desc:[this.stock.desc],
categories:fb.array([ //用法原因:股票的类型在定义的时候就是string的数组Array<string>,[true,true,null]
//this.stock.categories.indexOf(this.categories[0])!=-1 this.stock.categories里面有IT就返回true
new FormControl(this.stock.categories.indexOf(this.categories[0])!=-1),
new FormControl(this.stock.categories.indexOf(this.categories[1])!=-1),
new FormControl(this.stock.categories.indexOf(this.categories[2])!=-1),
],this.categoriesSelectValidator)
});
##3 在【修改表单】模板中展示错误信息
<p>
{{stock.name}}
</p>
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">股票信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal" [formGroup]="formModel">
<div class="box-body">
<!-- ##【1】校验name 内置校验器-->
<div class="form-group" [class.has-error]="formModel.hasError('minlength','name')||
formModel.hasError('required','name')">
<label for="name" class="col-sm-2 control-label">股票名称</label>
<div class="col-sm-6">
<input type="text" class="form-control" formControlName="name" id="name" placeholder="股票名称" >
</div>
<span class="help-block" [class.hidden]="!formModel.hasError('required','name')" >股票名称是必填项!</span>
<span class="help-block" [class.hidden]="!formModel.hasError('minlength','name')">股票名称长度至少3位!</span>
</div>
<!-- ##【2】校验price 内置校验器 -->
<div class="form-group" [class.has-error]="formModel.hasError('required','price')">
<label for="price" class="col-sm-2 control-label" >股票价格</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="price" formControlName="price" placeholder="股票价格">
</div>
<span class="help-block" [class.hidden]="!formModel.hasError('required','price')" >股票价格是必填项!</span>
</div>
<!-- ##【3】校验categories 自定义校验器 -->
<!-- 【1】将整个checkbox组绑定到后台的categories -->
<div class="form-group" formArrayName="categories" [class.has-error]="formModel.hasError('categoriesLength',
'categories')" >
<label for="categories" class="col-sm-2 control-label" >股票类型</label>
<!-- 【2】循环初始化数组categories -->
<div *ngFor="let category of categories;let i=index;" class=" col-sm-2">
<div class="checkbox ">
<label>
<!-- 【3】将每个checkbox绑定到categories的每个项,因为是绑定到变量上所以加[formControlName] -->
<input [formControlName]='i' type="checkbox" > {{category}}
</label>
</div>
</div>
<span class="help-block" [class.hidden]="!formModel.hasError('categoriesLength','categories')" >
请至少选择一个类型!</span>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-default">取消</button>
<!-- 控制表单不合法时,保存按钮不可点击 -->
<button type="submit" [disabled]="formModel.invalid" class="btn btn-info pull-right" (click)="save()" >保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->
表单样式如下:
##【添加表单】模板展示错误信息:
<p>
{{stock.name}}
</p>
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">股票信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal" [formGroup]="formModel">
<div class="box-body">
<!-- ##【1】校验name -->
<div class="form-group" [class.has-error]="formModel.get('name').touched &&
(formModel.hasError('minlength','name')||formModel.hasError('required','name'))">
<label for="name" class="col-sm-2 control-label">股票名称</label>
<div class="col-sm-6">
<input type="text" class="form-control" formControlName="name" id="name" placeholder="股票名称" >
</div>
<span class="help-block" [class.hidden]="formModel.get('name').untouched||
!formModel.hasError('required','name')" >股票名称是必填项!</span>
<span class="help-block" [class.hidden]="formModel.get('name').untouched||
!formModel.hasError('minlength','name')">股票名称长度至少3位!</span>
</div>
<!-- ##【2】校验price -->
<div class="form-group" [class.has-error]="formModel.get('price').touched
&& formModel.hasError('required','price')">
<label for="price" class="col-sm-2 control-label" >股票价格</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="price" formControlName="price" placeholder="股票价格">
</div>
<span class="help-block" [class.hidden]="formModel.get('price').untouched||!formModel.hasError('required',
'price')" >股票价格是必填项!</span>
</div>
<!-- ##【3】校验categories 自定义校验器 -->
<!-- 【1】将整个checkbox组绑定到后台的categories -->
<div class="form-group" formArrayName="categories" [class.has-error]="formModel.get('categories').touched &&
formModel.hasError('categoriesLength','categories')" >
<label for="categories" class="col-sm-2 control-label" >股票类型</label>
<!-- 【2】循环初始化数组categories -->
<div *ngFor="let category of categories;let i=index;" class=" col-sm-2">
<div class="checkbox ">
<label>
<!-- 【3】将每个checkbox绑定到categories的每个项,因为是绑定到变量上所以加[formControlName] -->
<input [formControlName]='i' type="checkbox" > {{category}}
</label>
</div>
</div>
<span class="help-block" [class.hidden]="formModel.get('categories').untouched||
!formModel.hasError('categoriesLength','categories')" >请至少选择一个类型!</span>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-default">取消</button>
<!-- 控制表单不合法时,保存按钮不可点击 -->
<button type="submit" [disabled]="formModel.invalid" class="btn btn-info pull-right" (click)="save()" >保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->