邁向angularjs2系列(7):表單

目錄css

 一:校驗表單的使用html

1.搭建腳手架git

2.校驗表單的使用github

3.select下拉列表的用法npm

一: 校驗表單的使用

對於CRUD型的應用,表單是必備組件。bootstrap

1.搭建腳手架數組

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

npm installangular2

npm startapp

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

相關文章
相關標籤/搜索