Angular 响应式表单实战

将对下图所示的表单进行数据模型的创建和数据模板的绑定

【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 -->



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值