zoukankan      html  css  js  c++  java
  • 迈向angularjs2系列(7):表单

    目录

     一:校验表单的使用

    1.搭建脚手架

    2.校验表单的使用

    3.select下拉列表的用法

    一: 校验表单的使用

    对于CRUD型的应用,表单是必备组件。

    1.搭建脚手架

    git clone https://github.com/mgechev/switching-to-angular2.git  form1

    npm install

    npm start

    app目录删掉所有内容后,新建form目录,form目录创建index.html和app.ts

    index.html是默认内容。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>

    app.ts只是简单的App组件和启动函数。

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    @Component({
      selector: 'app',
      template: `
        <div>初始状态</div>
      `
    })
    class App {}
    
    bootstrap(App);

    打开http://localhost:5555/dist/dev/form/,可看见预先填写的字符串。

     准备就绪

     2.校验表单的使用

    分为3个部分:

    第一部分:表单指令集和PROVIDERS引入,以及装饰器准备

    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    FORM_DIRECTIVES是表单指令集,
    FORM_PROVIDERS是内置的PROVIDERS数组。
    组件要使用导入的内容,那么装饰器就要提供相应的属性。
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles:[],
      directives:[FORM_DIRECTIVES],
      providers:[FORM_PROVIDERS]
    })

    第二部分:form标签使用ngForm指令

    <form #f="ngForm" (ngSubmit)="login()">
        <!--名称为f的表单,可用来引用当前form-->
    </form>

    当angular2发现这样的form标签,而且含有ngForm指令,就会把它当做form指令来增强了。 (ngSubmit)="login()" 当然是提交咯。

    第三部分:对input等进行表单校验

    <form #f="ngForm" (ngSubmit)="login()">
       <input id="nameInput" type="text" required ngControl="nameInput" minlength="6" maxlength="11"/>
    </form>

    这里使用的ngControl指令会在表单的值发生改变时进行校验,同时为校验的不同阶段添加class类,还会扩展required属性的语义,

    form不同的class类:

    ng-untouched。控件还没有被访问过。

    ng-touched。控件已经被访问过。

    ng-pristine。控件的值没有被修改。

    ng-dirty。控件的值已经被修改过。

    ng-valid。控件上所绑定的所有校验器都返回了true。

    ng-invalid。控件上所绑定的某个校验器返回了false。

    比如

    app.html:

    <form #f="ngForm" (ngSubmit)="login()">
    
      <lable>用户名:</lable>
      <br/>
       <input id="nameInput" type="text" required ngControl="name" minlength="11" maxlength="11"/>
       <br/>
      <span>调试打印:{{f.valid}}</span>
    </form>

    app.ts:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
          //边框
        }`
      ],
      directives:[FORM_DIRECTIVES],
      providers:[FORM_PROVIDERS]
    })
    class App {}
    
    bootstrap(App);

    由于输入不合法,会会有红色边框

    3.select下拉列表的用法

    我们以组件的方式来开发这个select下拉列表。

    首先,组件代码都准备好。

    app新建form-select目录,目录下创建app.html、app.ts、index.html。

    类似

    index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>
    默认首页代码

    注意,里面有boostrap引入,所以可以直接的使用bootstrap的样式哦。

    app.html:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `select.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
    //如果不合法会有红色的边框
      ],
      directives:[FORM_DIRECTIVES],
      providers:[FORM_PROVIDERS]
    })
    class App {
      youLike:string[]=[
        "艾莎","安娜","汉斯","阿伦黛尔"
      ]
      //冰雪奇缘的角色
    }
    
    bootstrap(App);

     首先使用ngFor指令把youLike数组遍历到option选项中。

    <select class="form-control">
          <option *ngFor="#yL of youLike" [value]="yL">
            {{yL}}
          </option>
        </select>

    然后使用ngControl指令进行校验,添加required属性、使用ngModel获得选择项。

    <select class="form-control" required ngControl="youLike"[(ngModel)]="youLike">
          <option *ngFor="#yL of youLikes" [value]="yL">
            {{yL}}
          </option>
        </select>
          <span>调试:youLike选择项是{{youLike}}</span>

    浏览器显示结果

    二: 表单校验详解

    1.自定义控件的校验器

    虽然angular2提供了一组预定义好的校验器,但是并不能覆盖各种各样的格式。这里我们自定义一个email校验器。

    Step1:写好校验函数

    校验函数接收value值为参数,没有值或者不匹配,返回null,否则返回{"invalidEmail":true}。

    function validateEmail(emailControl){
      var emailReg=/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/;
    //正则
      if(!emailControl||emailReg.test(emailControl.value)){
        return null;
      }else{
        return {"invalidEmail":true}
      }
    }

    step2:把校验函数包装到指令中。

    import {NG_VALIDATORS} from "@angular/common";
    import {Directive} from "@angular/core";
    //引入NG_VALIDATORS和Directive
    @Directive({
      selector:"[email-input]",
      //校验指令定义成属性
      providers: [{ provide: NG_VALIDATORS, useValue: validateEmail, multi: true }]
      //使用NG_VALIDATORS定义了单个provider,我们注射了绑定的值。
    })
    class EmailValidator{
    
    }

    step3:email控件上增加email-input属性。

    <input id="emailInput" class="form-control" 
                 email-input 
                 type="text" ngControl="email"
                 [(ngModel)]="email"/>

    step4:到组件上挂载email-input指令。

    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
      ],
      directives:[FORM_DIRECTIVES,EmailValidator],
      //EmailValidator指令添加到指令选项,就可以使用了
      providers:[FORM_PROVIDERS]
    })
    class App {}

    打开http://localhost:5555/dist/dev/email-validate/

    完整的app.ts代码:

    ch7-forms/form1/app/email-validate/app.ts:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    import {NG_VALIDATORS} from "@angular/common";
    import {Directive} from "@angular/core";
    //引入NG_VALIDATORS和Directive
    function validateEmail(emailControl){
      var emailReg=/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/;
      if(!emailControl||emailReg.test(emailControl.value)){
        return null;
      }else{
        return {"invalidEmail":true}
      }
    }
    
    @Directive({
      selector:"[email-input]",
      //校验指令定义成属性
      providers: [{ provide: NG_VALIDATORS, useValue: validateEmail, multi: true }]
      //使用NG_VALIDATORS定义了单个provider,我们注射了绑定的值。
    })
    class EmailValidator{
    
    }
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
      ],
      directives:[FORM_DIRECTIVES,EmailValidator],
      providers:[FORM_PROVIDERS]
    })
    class App {}
    
    bootstrap(App);
    email自定义校验

    2.ngForm指令

     新建ng-form目录,目录下创建index.html、app.ts、app.html。

    index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>
    index.html也就是入口文件

    app.html暂时还使用之前的form代码:

    <form #f="ngForm" (ngSubmit)="login()">
    
      <lable>用户名:</lable>
      <br/>
       <input id="nameInput" type="text" required ngControl="name" minlength="11" maxlength="11"/>
       <br/>
      <span>调试打印:{{f.valid}}</span>
    </form>
    View Code

    app.ts暂时使用之前的代码:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
      ],
      directives:[FORM_DIRECTIVES],
      providers:[FORM_PROVIDERS]
    })
    class App {}
    
    bootstrap(App);
    View Code

    打开http://localhost:5555/dist/dev/ng-form/,会有如下结果

    现在为了演示form元素的用法,定义control-error组件,用来显示报错信息。

    step1:定义ControlErrors组件

    import{NgControl,NgForm} from "@angular/common";
    import{Host} from "@angular/core"
    //NgControl类是一个抽象类,用来代表angular表单
    //Host是一个装饰器,与依赖注入有关
    @Component({
      template: `<div>{{currentError}}</div>`,
      selector: 'control-errors',
      inputs: ['control', 'errors']
    })
    //组件的输入是control和errors
    class ControlErrors {
      errors: Object;
      control: string;
      constructor(@Host() private formDir: NgForm) {}
      get currentError() {
        let control = this.formDir.controls[this.control];
        let errorMessages = [];
        if (control && control.touched) {
          errorMessages = Object.keys(this.errors)
            .map(k => control.hasError(k) ? this.errors[k] : null)
            .filter(error => !!error);
        }
        return errorMessages.pop();
      }
    }

    step2:组件注册

    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
      ],
      directives:[FORM_DIRECTIVES,ControlErrors],
    //组件注册
      providers:[FORM_PROVIDERS ]
    })
    class App {
      
    }

    step3:使用control-errors组件

    <form #f="ngForm" >
      <div class="form-group">
        <label class="control-label" for="realNameInput">Real name</label>
        <div>
          <input id="realNameInput" class="form-control"
                 type="text" ngControl="name"
                 required maxlength="5">
          <control-errors control="name"
                          [errors]="{
              'required': 'Real name is required',
              'maxlength': 'The maximum length of the real name is 5characters'
            }"></control-errors>
        </div>
      </div>
    </form>

    打开http://localhost:5555/dist/dev/ng-form/,使得input框获得焦点,然后失去焦点,浏览器结果如图

    OK

    最终完整的代码:

    app.html:

    <form #f="ngForm" >
      <div class="form-group">
        <label class="control-label" for="realNameInput">Real name</label>
        <div>
          <input id="realNameInput" class="form-control"
                 type="text" ngControl="name"
                 required maxlength="5">
          <control-errors control="name"
                          [errors]="{
              'required': 'Real name is required',
              'maxlength': 'The maximum length of the real name is 5characters'
            }"></control-errors>
        </div>
      </div>
    </form>
    模板

    app.ts:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{FORM_DIRECTIVES,FORM_PROVIDERS} from '@angular/common';
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      styles: [
          `input.ng-dirty.ng-invalid{
          border:1px solid red;
        }`
      ],
      directives:[FORM_DIRECTIVES],
      providers:[FORM_PROVIDERS]
    })
    class App {}
    
    bootstrap(App);
    View Code

    index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>
    View Code

    3.双向数据绑定

    ngModel指令轻松实现双向数据绑定。选择器为[(ngModel)]。

    目录结构

    ch7-forms/form1/app/ng-model/app.ts:

    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{NgModel} from "@angular/common";
    
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      directives:[NgModel]
    })
    class App {
      name:string;
    }
    
    bootstrap(App);
    //非常简单的例子

    ch7-forms/form1/app/ng-model/app.html:

    <input type="text" [(ngModel)]="name"/>
    <div>{{name}}</div>

    ch7-forms/form1/app/ng-model/index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>
    View Code

     打开http://localhost:5555/dist/dev/ng-model/,浏览器结果如图,当修改了input的值,label会自动刷新。

    三: 表单数据的存储

    表单数据很多,并非一两个,我们可以通过把数据以属性的形式挂载到某个对象(实例上),做非常简洁的存储。

    只做一个简单的例子:

    ch7-forms/form1/app/user/app.html:

    <input type="text" [(ngModel)]="user.name"/>
    <button (click)="getUser(user)">获得user对象</button>
    View Code

    ch7-forms/form1/app/user/user.ts:

    export class User{
      name:string;
    }
    //数据从logic分离出来了
    //实际情况会有更多的属性

    ch7-forms/form1/app/user/app.ts:

    //顶级组件的代码
    import {Component} from '@angular/core';
    import {bootstrap} from '@angular/platform-browser-dynamic';
    import{NgModel} from "@angular/common";
    import{User}from "./user";
    
    @Component({
      selector: 'app',
      templateUrl:"./app.html",
      directives:[NgModel]
    })
    class App {
      user=new User();
      getUser(user){
        console.log(user)
      }
    }
    
    bootstrap(App);

    ch7-forms/form1/app/user/index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= TITLE %></title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
      <!-- inject:css -->
      <!-- endinject -->
    </head>
    <body>
    
      <app>Loading...</app>
      <!-- inject:js -->
      <!-- endinject -->
      <%= INIT %>
    </body>
    </html>
    View Code

    当input框输入值之后,会打印对象

    另外关于提交有一个小方法阻止重复提交。

    <form #f="ngForm" (ngSubmit)="login()" [hidden]="submitted">
    
    </form>

    一开始设置submitted为false,那么表单就可以通过login来提交了,而一旦提交完成,设置为true,那么就隐藏起form,也就不会有再次提交了。

  • 相关阅读:
    Windows修改MySQL用户root密码
    ORA-24247: 网络访问被访问控制列表 (ACL) 拒绝
    DM8 HUGE表使用小技巧
    DEM 安装部署
    【.NET 框架】—— Dapper框架的高级应用(二)
    JWT理论理解
    SqlServer使用表变量或临时表遍历数据
    NPOI Excel Helper
    Celery异步分布队列
    Django-Admin和第三方插件Xadmin
  • 原文地址:https://www.cnblogs.com/chenmeng2062/p/7105783.html
Copyright © 2011-2022 走看看