模板驱动表单学习

简介: 模板驱动表单学习

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 类来给用户提供无效控件的视觉反馈。



目录
相关文章
|
7月前
|
移动开发 JavaScript 前端开发
四种方式解决页面国际化问题——步骤详解
四种方式解决页面国际化问题——步骤详解
234 0
|
6月前
基于EasyUI的后台管理系统页面原型_示例图_下载地址
基于EasyUI的后台管理系统页面原型_示例图_下载地址
36 0
|
3月前
|
缓存 前端开发 数据可视化
前端基础(七)_表单的基本组成与使用
本文详细介绍了HTML表单的基本组成和使用,包括`<form>`标签、`<input>`表单域、`<select>`下拉列表、`<textarea>`多行文本域等元素。文章解释了表单的提交方式(GET和POST)、表单域的各种类型(文本、密码、单选按钮、复选框等)、提交按钮和重置按钮的作用,以及如何通过`<label>`标签提高表单的可访问性。此外,还讨论了表单元素的属性,如`readonly`、`disabled`、`maxlength`等。
34 1
|
4月前
|
数据采集 前端开发 开发者
Angular表单控件详解:掌握模板驱动与响应式表单的精髓,让Web应用中的数据采集工作变得高效又简单,彻底告别繁琐的表单处理流程
【8月更文挑战第31天】表单是 Web 应用的关键组件,用于用户登录、注册及信息提交。Angular 作为成熟前端框架,提供了强大的表单处理功能,包括模板驱动与响应式表单。本文通过技术博客形式,详细介绍这两种表单控件,并提供示例代码,展示如何利用它们简化表单处理流程,提高开发效率。首先介绍简单的模板驱动表单,然后讲解基于 RxJS 的响应式表单,适用于复杂逻辑。通过本文,你将学会如何高效地使用 Angular 表单控件,提升应用的用户体验。
48 0
|
前端开发 JavaScript 数据可视化
漏刻有时数据可视化大屏核心框架模版更换前端模版操作(1)HTML文件分离及访问显示
漏刻有时数据可视化大屏核心框架模版更换前端模版操作(1)HTML文件分离及访问显示
83 0
|
存储 JSON JavaScript
一份配置轻松搞定表单渲染,配置式表单渲染器在袋鼠云的实现思路与实践
本文将为大家详细介绍配置式表单渲染器在袋鼠云的实现思路与实践,在对接新的数据源时,可以不再关心表单渲染相关问题,从数据源中心新建数据源一直到数据源在数据同步模块的应用,全链路的表单都可以通过配置化的方式解决。
72 0
|
XML 数据格式 开发者
流程表单初体验
流程表单初体验
|
前端开发
前端学习案例-自定义navLink&自定义导航1
前端学习案例-自定义navLink&自定义导航1
79 0
前端学习案例-自定义navLink&自定义导航1
|
JavaScript
【Vue 开发实战】实战篇 # 40:自己封装一个支持自动校验的表单项
【Vue 开发实战】实战篇 # 40:自己封装一个支持自动校验的表单项
145 0
【Vue 开发实战】实战篇 # 40:自己封装一个支持自动校验的表单项