模板驱动表单学习

简介: 模板驱动表单学习

Angular知识学习(一)中有讲述到表单的知识,不过那是最基础的演示,在之后的学习中又了解到模板驱动表单,所以考虑对之前的表单案例进行重构,完善表单功能,让案例更接近应用。


根据官网模板驱动表单的知识内容,我们重新构建人员登记表单,主要分为以下步骤:

  1. 创建 Uuser 模型类
  2. 创建控制此表单的组件
  3. 创建具有初始表单布局的模板。
  4. 使用 ngModel 双向数据绑定语法把数据属性绑定到每个表单输入控件。
  5. 往每个表单输入控件上添加 name 属性 (attribute)。
  6. 添加自定义 CSS 来提供视觉反馈。
  7. 显示和隐藏有效性验证的错误信息。
  8. 使用 ngSubmit 处理表单提交。
  9. 禁用此表单的提交按钮,直到表单变为有效。


创建User模型类


使用 Angular CLI 命令 ng g class 生成一个名叫 Uuer 的新类:


ng g class model/uuer
复制代码


内容如下:


export class Uuser {
  constructor(
    public name: string,
    public sex: string,
    public city: string,
    public hobbies: any[],
    public remark: string
  ) {
  }
}
复制代码


该类主要包含五个属性,分别是姓名、性别、城市、爱好和备注。其中爱好有多个,所以用数组来表示。


创建表单组件


使用 Angular CLI 命令 ng g component 生成一个名叫 UserForm 的新组件:


ng g component components/userForm
复制代码


因为模板驱动的表单位于它们自己的模块,所以在使用表单之前,需要将 FormsModule 添加到应用模块的 imports 数组中。对  app.module.ts  进行修改:


import { FormsModule }   from '@angular/forms';
  imports: [
    BrowserModule,
    FormsModule
  ]
复制代码


有两处更改


  1. 导入 FormsModule
  2. FormsModule 添加到 ngModule 装饰器的 imports 列表中,这样应用就能访问模板驱动表单的所有特性,包括 ngModel


关于表单内容的分析,官方文档写的非常详细,这里我只针对本案例中的难点进行分析,其他细节部分可以阅读官方文档。


user-form.component.html内容如下:


<h2>人员登记系统</h2>
<div class="container">
  <div [hidden]="submitted">
    <form (ngSubmit)="onSubmit()" #form="ngForm">
      <div class="form-group">
        <label for="name">姓 名</label>
        <input class="form-control" id="name" type="text" required name="name" [(ngModel)]="user.name" #name="ngModel">
        <span [hidden]="name.valid || name.pristine" class="alert alert-danger">Name is required</span>
      </div>
      <div class="form-group">
        <label>性 别 </label> &nbsp;
        <div class="radio-inline">
          <input type="radio" value="男" name="sex" id="man" [(ngModel)]="user.sex" > <label for="man">男</label>
        </div>
        <div class="radio-inline">
          <input type="radio" value="女" name="sex" id="woman" [(ngModel)]="user.sex" > <label for="woman">女</label>
        </div>
      </div>
      <div class="form-group">
        <label for="city">城 市</label>
        <select class="form-control" id="city" required name="city" [(ngModel)]="user.city" #city="ngModel">
          <option *ngFor="let ct of cities" [value]="ct">{{ct}}</option>
        </select>
        <span [hidden]="city.valid || city.pristine" class="alert alert-danger">City is required</span>
      </div>
      <div class="form-group">
        <label for="hobby">爱 好</label>&nbsp;
        <span *ngFor="let item of user.hobbies;let key=index" class="checkbox-inline">
          <input type="checkbox" [id]="'check'+key" [(ngModel)]="item.status" [name]="'check'+key"><label [for]="'check'+key">{{item.title}}</label>
          &nbsp;&nbsp;
        </span>
      </div>
      <div class="form-group">
        <label for="remark">备 注</label>
        <textarea class="form-control" id="remark" type="text" required name="remark" [(ngModel)]="user.remark" #remark="ngModel"></textarea>
        <span [hidden]="remark.valid || remark.pristine" class="alert alert-danger">remark is required</span>
      </div>
      <button type="submit" class="btn btn-success" [disabled]="!form.valid">Submit</button>
      <button type="button" class="btn btn-default" (click)="newUser();form.reset()">New User</button>
    </form>
  </div>
  <div [hidden]="!submitted">
    <h2>You submitted the following:</h2>
    <div class="row">
      <div class="col-xs-3">姓 名</div>
      <div class="col-xs-9">{{ user.name }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">性 别</div>
      <div class="col-xs-9">{{  user.sex }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">城 市</div>
      <div class="col-xs-9">{{  user.city }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">爱 好</div>
      <div class="col-xs-9">
        <span *ngFor="let item of user.hobbies">
          <span *ngIf="item.status == 1">{{item.title}}</span>&nbsp;&nbsp;
        </span>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-3">备 注</div>
      <div class="col-xs-9">{{  user.remark }}</div>
    </div>
    <br>
    <button class="btn btn-primary" (click)="submitted=false">Edit</button>
  </div>
</div>
复制代码


同官方文档中案例相比,本文的案例增加了单选框和多选框的应用,尤其是多选框,考虑到数据的双向绑定,所以必须对 user.hobbies 属性进行初始化,通过勾选前台按钮,来改变 user.hobbies的状态值,从而达到信息记录的目的。

user-form.component.ts内容如下:


import { Component, OnInit } from '@angular/core';
import { Uuser } from '../../model/uuser';
@Component({
  selector: 'app-user-form',
  templateUrl: './user-form.component.html',
  styleUrls: ['./user-form.component.css']
})
export class UserFormComponent implements OnInit {
  submitted = false;
  cities = ['北京', '上海', '广州 ', '深圳', '杭州', '武汉', '成都'];
  hobbies = ['唱歌', '跳舞', '跑步', '健身', '游泳'];
  user = new Uuser('', '男', this.cities[1], [], '');
  constructor() { }
  ngOnInit(): void {
    this.setHobbies();
  }
  //每个User对象都初始化hobby属性,只是status值默认为0,通过前台勾选来修改status
  setHobbies() {
    // tslint:disable-next-line: prefer-for-of
    for (let i = 0; i < this.hobbies.length; i++) {
      this.user.hobbies.push(
        {
          title: this.hobbies[i],
          status: 0
        }
      );
    }
  }
  onSubmit() {
    this.submitted = true;
  }
  newUser() {
    this.user = new Uuser('', '', '', [], '');
    this.setHobbies();
  }
}
复制代码


为了增加前台表单的观赏性,对表单的 CSS 样式做了一些修改。


首先是 styles.css,引入 Bootstrap 样式,对表单整体框架显示进行优化。


@import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');
复制代码


其次是 user-form.component.css


h2{
  text-align: center;
}
.ng-valid[required], .ng-valid.required  {
  border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form)  {
  border-left: 5px solid #a94442; /* red */
}
复制代码


可以在输入框的左侧添加带颜色的竖条,当在必填字段输入有效内容时,输入框左侧会变为绿色,否则视为无效,变为红色。


页面测试


对上述的代码进行验证,首先完整走一遍逻辑过程。


1.jpg


我们来梳理一下流程,首先是维护一个人的基本信息,点击 Submit 按钮提交表单,即跳转到人员信息查看页面,再点击 Exit 按钮退回到人员维护页面,点击 New User 按钮,清空页面内容,重新录入人员信息,再次提交表单可正常跳转到人员信息查看页面。


测试过程中可以发现,当必填项不填写内容,Submit 按钮始终是灰色的,即无法点击提交,此处是对整个表单进行有效验证,在实际应用中也是很有必要的。


关于性别单选框有一点需要注意:平时我们设置单选框的默认值,加上 checked 即可,但是由于在当前案例中使用了双向数据绑定,所以该属性不起作用,必须给 user.sex 设置默认值,从而实现单选框的默认选定。


关于爱好多选框,从数据双向绑定的角度来看,是无法向 user.hobbies 中增加数据,多选框的勾选只是状态值的改变,所以在 user-form.component.ts 文件中会增加一个 setHobbies 方法。


总结


本文对于 Angular 表单的使用进行了优化,利用框架特性来支持数据修改、验证和更多操作:


  • Angular HTML 表单模板。
  • 带有 @Component 装饰器的表单组件类。
  • 通过绑定到 NgForm.ngSubmit 事件属性来处理表单提交。
  • 模板引用变量,例如 #form#name
  • [(ngModel)] 语法用来实现双向数据绑定。
  • name 属性的用途是有效性验证和对表单元素的变更进行追踪。
  • 指向 input 控件的引用变量上的 valid 属性,可用于检查控件是否有效、是否显示/隐藏错误信息。
  • 通过绑定到 NgForm 的有效性状态,控制 Submit 按钮的禁用状态。
  • 定制 CSS 类来给用户提供无效控件的视觉反馈。



目录
相关文章
|
3天前
|
编译器 C++
C++-模板基础
C++-模板基础
24 0
|
10月前
layui框架实战案例(11):表单自定义验证规则
layui框架实战案例(11):表单自定义验证规则
127 0
|
3天前
|
数据可视化 数据挖掘 API
5 款热门的表单设计器推荐
5 款热门的表单设计器推荐
|
10月前
|
前端开发 JavaScript 数据可视化
漏刻有时数据可视化大屏核心框架模版更换前端模版操作(1)HTML文件分离及访问显示
漏刻有时数据可视化大屏核心框架模版更换前端模版操作(1)HTML文件分离及访问显示
63 0
|
12月前
|
XML 数据格式 开发者
流程表单初体验
流程表单初体验
|
前端开发
前端学习案例-自定义navLink&自定义导航1
前端学习案例-自定义navLink&自定义导航1
61 0
前端学习案例-自定义navLink&自定义导航1
|
存储 前端开发 数据可视化
实现一个表单设计器我们需要知道的
表单功能一直是前端项目中比不可少的一块功能,如果有个项目需要在两个月内开发200个左右表单,那我们应该怎么办?加班加点也是能搞出来的,那质量有保证么,这是我们就需要开发一个可以通过可视化交互设计表单的功能。下面和大家分享下我在开发这款表单设计器时使用的技术能力以及整个的设计思路。
|
前端开发 JavaScript 数据安全/隐私保护
form表单常见控件应用,实例讲解注册页面的开发【2020网页综合笔记03】
form表单常见控件应用,实例讲解注册页面的开发【2020网页综合笔记03】
162 0
form表单常见控件应用,实例讲解注册页面的开发【2020网页综合笔记03】
|
安全 数据库 数据安全/隐私保护
表单的 9 种设计技巧【下】
表单是信息添加、录入的通用形式,合理的表单设计能减轻用户负担。这里码匠提供的一些表单设计的简单技巧的下篇。
178 0
表单的 9 种设计技巧【下】
|
安全 数据安全/隐私保护 对象存储
表单的 9 种设计技巧【上】
表单是信息添加、录入的通用形式,合理的表单设计能减轻用户负担。这里码匠提供了一些表单设计的简单技巧。
689 0
表单的 9 种设计技巧【上】

相关实验场景

更多