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,也就不会有再次提交了。

  • 相关阅读:
    Java vs Python
    Compiled Language vs Scripting Language
    445. Add Two Numbers II
    213. House Robber II
    198. House Robber
    276. Paint Fence
    77. Combinations
    54. Spiral Matrix
    82. Remove Duplicates from Sorted List II
    80. Remove Duplicates from Sorted Array II
  • 原文地址:https://www.cnblogs.com/chenmeng2062/p/7105783.html
Copyright © 2011-2022 走看看