Angular 2 + 折騰記 :(7) 初步瞭解表單:模板驅動及資料驅動及脫坑要點
前言
表單在整個系統中的作用相當重要,這裡主要扯下響應表單的實現方式。
首先需要操作表單的模組引入這兩個模組;
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
表單控制元件響應的幾種狀態
模板驅動表單依賴FormsModule
,資料驅動的表單依賴FormsModule,ReactiveFormsModule
一般做表單校驗及操作推薦用資料驅動的方式,好維護和理解。。
模板驅動
模板驅動:主要是依賴[(ngModel)]
和#scope_var
以及原生表單控制元件屬性(require
minlenght
,maxlength
等)來操作表單的那的值亦或者校驗
- 一個最簡單的例子
<!--#UserName 是區域性變數,若是有ngmodel,拿到的就是一個響應物件,若是非ngmodel繫結的,則是dom元素程式碼-->
<!--testform這個區域性變數儲存了表單的所有相關資訊-->
<!--ngSubmit是用來觸發表單提交的-->
<!--ngModel相應變數的值-->
<!--$event是原生dom物件-->
<form #testform="ngForm" (ngSubmit)="Submit(testform.value,testform.valid)" >
<label for="username">Name</label>
<input type="text" id="username" #UserName="username" class="form-control"
required minlength="4" maxlength="24"
name="username" [(ngModel)]="username" [ngModelChange]="validate($event)">
<div *ngIf="UserName.valid || (UserName.pristine && !testform.submitted)" >
您輸入的值有誤,請重新輸入
</div>
<button type="submit" >提交</button>
</form>
有兩種方式處理來對上面的表單做校驗;
- 在
Submit()
函式內,在點選提交的時候對整個表單一一去判斷,傳統方式基本這樣 - 每個控制元件輸入的時候對應去觸發對應的事件做校驗,比如
[ngModelChange]
來處理雙向繫結的值校驗
資料驅動(Reactive Form)
響應式表表單:原理是一開始就構建整個表單,表單的值通過特殊指令formControlName
一一關聯(類似ngModel
);
相關名詞:
- FormGroup
: 用來追蹤表單控制元件有效狀態及值 =》 可以理解為獲取且可以操作整個表單的資料
- FormBuilder
:表單資料構建工具[構建初始表單],簡化構建程式碼(包括了new FormGroup()
,new FormControl()
,new FormArray()
),FormGroup()
內建多種校驗方式
- formControlName
: 同步與FormGroup
構建表單內相同欄位的值!
專案中的案例
- html
<div [@flyIn]="true">
<div class="beautify-form" *ngIf="!showLoading">
<div class="page-header">
歡迎登入
</div>
<form [formGroup]="form" (ngSubmit)="onSubmit(form)">
<div class="form-group" [ngClass]="{ 'has-danger': form.controls.UserName.invalid && form.controls.UserName.value ,'has-success': form.controls.UserName.valid && form.controls.UserName.value }">
<div class="input-group input-group-lg">
<span class="input-group-addon fpd fpd-ordinarylogin1"></span>
<input type="text" class="form-control" formControlName="UserName" placeholder="手機號碼 \ 郵箱 ">
</div>
<div class="form-control-feedback" *ngIf="(form.controls.UserName.dirty || form.controls.UserName.pristine) && form.controls.UserName.invalid && form.controls.UserName.value">賬號不符合規範</div>
<div class="form-control-feedback" *ngIf="(form.controls.UserName.dirty || form.controls.UserName.pristine) && form.controls.UserName.valid && form.controls.UserName.value">賬號符合規範</div>
</div>
<div class="form-group" [ngClass]="{ 'has-danger': form.controls.PassWord.invalid && form.controls.PassWord.value ,'has-success': form.controls.PassWord.valid && form.controls.PassWord.value }">
<div class="input-group input-group-lg">
<span class="input-group-addon fpd fpd-mima"></span>
<input type="PassWord" class="form-control" formControlName="PassWord" placeholder="請輸入密碼">
</div>
<div class="form-control-feedback" *ngIf="(form.controls.PassWord.dirty || form.controls.PassWord.pristine) && form.controls.PassWord.invalid && form.controls.PassWord.value ">密碼不符合規範,請重新輸入</div>
<div class="form-control-feedback" *ngIf="(form.controls.PassWord.dirty || form.controls.PassWord.pristine) && form.controls.PassWord.valid && form.controls.PassWord.value ">密碼符合規範</div>
</div>
<div class="form-group ">
<div class="flex">
<div class="beautify-wrap flex-wrap">
<input type="checkbox" class="beautify-checkbox" name="rememberme" id="rememberAccount" formControlName="rememberAccount">
<label for="rememberAccount"></label>記住賬號
</div>
<!--<a [routerLink]="['/account/reset-pw']">忘記密碼</a>-->
</div>
</div>
<div class="message-tips" *ngIf="messageTips">
<i class="fpd fpd-error"></i> {{messageTips}}
</div>
<div class="form-group ">
<button class="btn btn-lg btn-outline-success btn-block" type="submit" [disabled]="form.invalid">登入</button>
</div>
<div class="form-group">
<span class="noaccount-notify">沒有賬號?點選</span><a [routerLink]="['/account/collect']" class="collect-user">使用者登記</a>
</div>
</form>
</div>
<div class="loading" *ngIf="showLoading">
<app-mit-loading [option]="'load4'"></app-mit-loading>
</div>
</div>
- component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms'; // 引入表單的一些特性
import { Router } from '@angular/router';
import { AccountService } from '../../services/account.service';
import { environment } from '../../../../../environments/environment';
import { flyIn } from '../../../../animation/flyIn';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
animations: [flyIn]
})
export class LoginComponent implements OnInit, OnDestroy {
public form: FormGroup; // 表單物件
public showLoading = false;
public messageTips: string;
public login_subscribe: any;
// Validators的寫法注意事項
// v2.x版本這樣的寫法是可行的,v4有調整,不然不會生效
// 'UserName':'', [ Validators.compose([Validators.minLength(6)]
// v4+ , 第一位的''代表這個元素初始化構建為空值,類似未輸入狀態
// 'UserName': ['', Validators.compose([Validators.minLength(6)]
// Validators可選引數
// 1. required :必須驗證的,返回布林值
// 2. minLength : 最小長度
// 3. maxLenght: 最大長度
// 4. nullValidator : 空值判斷
// 5. coompose :多重判斷組合,下面有寫法
// 6. pattern是支援正則模式,正則謹記轉義轉義轉義
constructor(private fb: FormBuilder, private router: Router, private account: AccountService) {
this.form = fb.group({
'UserName': ['', Validators.compose([Validators.minLength(6) || Validators.pattern('(0|86|17951)?(-)?1[3,4,5,7,8,9]\\d{9}') || Validators.pattern('[\\.a-zA-Z0-9_-][email protected][a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+')])],
'PassWord': ['', Validators.compose([Validators.required, Validators.pattern('\\w{8,16}')])],
'rememberAccount': ['']
});
}
ngOnInit() {
}
// 登入事件
onSubmit(e) {
this.showLoading = true;
this.login_subscribe = this.account.login(e.value).subscribe((res) => {
console.log('省略。。。。。。')
}, (err) => {
this.showLoading = false;
});
}
ngOnDestroy() {
if (this.login_subscribe) {
this.login_subscribe.unsubscribe();
}
}
}
效果圖
巢狀表單
有些時候我們介面資料層次不可能只有一層,出現兩層三層都有可能;
這時候需要我們構建一個巢狀表單。。。
- html
v2-的寫法:表單的取值可以用controls
直接點出來
<div class="custom-card">
<div class="custom-card-body">
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row" formGroupName="RuleContent">
<div class="col-sm-12 col-md-12 col-lg-8 offset-lg-2">
<div class="form-group row" [ngClass]="{ 'has-danger': form.controls.RuleContent.controls.FenceName.invalid && form.controls.RuleContent.controls.FenceName.value ,'has-success': form.controls.RuleContent.controls.FenceName.valid && form.controls.RuleContent.controls.FenceName.value }">
<label tooltip="" class="col-sm-10 col-md-3 form-control-label col-lg-3 star">速度柵欄名稱</label>
<div class="col-sm-8 col-md-6 col-lg-6">
<input type="text" class="form-control" formControlName="FenceName" placeholder="柵欄名稱">
</div>
<div class="col-2 col-sm-4 col-lg-3 flex-align-center">
不超過十個字
</div>
</div>
<div class="form-group row" [ngClass]="{ 'has-danger': form.controls.RuleContent.controls.MaxSpeed.invalid && form.controls.RuleContent.controls.MaxSpeed.value ,'has-success': form.controls.RuleContent.controls.MaxSpeed.valid && form.controls.RuleContent.controls.MaxSpeed.value }">
<label tooltip="" class="col-sm-10 col-md-3 form-control-label col-lg-3 star">速度閾值</label>
<div class="col-sm-8 col-md-6 col-lg-6">
<input type="number" class="form-control" min="1" formControlName="MaxSpeed" placeholder="整數">
</div>
<div class="col-2 col-sm-4 col-lg-3 flex-align-center">
km/h
</div>
</div>
<div class="form-group row">
<div class="col-12 col-sm-10 col-md-6 offset-sm-2 offset-md-4 offset-lg-3">
<button type="submit" class="btn btn-primary" [disabled]="form.invalid">儲存</button>
<button type="button" class="btn btn-secondary" (click)="back()">取消</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
v4+的寫法 :巢狀表單的取值必須用.get()
來獲取,不然會報錯誤,具體原因是api改動了,看下官方文件就知道,改動了挺多(不僅僅這塊)
<div class="custom-card">
<div class="custom-card-body">
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row" formGroupName="RuleContent">
<div class="col-sm-12 col-md-12 col-lg-8 offset-lg-2">
<div class="form-group row" [ngClass]="{ 'has-danger': form.get('RuleContent.FenceName').invalid && form.get('RuleContent.FenceName').value ,'has-success': form.get('RuleContent.FenceName').valid && form.get('RuleContent.FenceName').value }">
<label tooltip="" class="col-sm-10 col-md-3 form-control-label col-lg-3 star">速度柵欄名稱</label>
<div class="col-sm-8 col-md-6 col-lg-6">
<input type="text" class="form-control" formControlName="FenceName" placeholder="柵欄名稱">
</div>
<div class="col-2 col-sm-4 col-lg-3 flex-align-center">
不超過十個字
</div>
</div>
<div class="form-group row" [ngClass]="{ 'has-danger': form.get('RuleContent.MaxSpeed').invalid && form.get('RuleContent.MaxSpeed').value ,'has-success': form.get('RuleContent.MaxSpeed').valid && form.get('RuleContent.MaxSpeed').value }">
<label tooltip="" class="col-sm-10 col-md-3 form-control-label col-lg-3 star">速度閾值</label>
<div class="col-sm-8 col-md-6 col-lg-6">
<input type="number" class="form-control" min="1" formControlName="MaxSpeed" placeholder="整數">
</div>
<div class="col-2 col-sm-4 col-lg-3 flex-align-center">
km/h
</div>
</div>
<div class="form-group row">
<div class="col-12 col-sm-10 col-md-6 offset-sm-2 offset-md-4 offset-lg-3">
<button type="submit" class="btn btn-primary" [disabled]="form.invalid">儲存</button>
<button type="button" class="btn btn-secondary" (click)="back()">取消</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
- components.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms'; // 引入表單的一些特性
// 動畫
import { fadeIn } from '../../../../../animation/fadeIn';
// 服務
import { SpeedFenceService } from '../speed-fence.service';
import { EventsService } from '../../../../../services/events-service.service';
@Component({
selector: 'app-modify',
templateUrl: './modify.component.html',
styleUrls: ['./modify.component.scss'],
animations: [fadeIn]
})
export class ModifyComponent implements OnInit {
public form: FormGroup;
public getId: any;
public id: number;
constructor(
private speedFenceService: SpeedFenceService,
private eventsService: EventsService,
private router: Router,
private activatedRoute: ActivatedRoute,
private fb: FormBuilder
) {
this.form = fb.group({
'ID': 0,
'RuleContent': this.fb.group({
'MaxSpeed': [0, Validators.compose([Validators.required, Validators.pattern('(([4-9][0-9])|(1[0-1][0-9])|(120))')])],
'FenceName': ['', Validators.compose([Validators.required, Validators.minLength(2), Validators.maxLength(10)])],
})
});
}
ngOnInit() {
this.checkAction();
// console.log(this.form);
}
// 獲取ID
checkAction() {
this.activatedRoute.params.subscribe((params: { id: string }) => {
console.log(params);
if (params.id) {
console.log(this.id);
this.id = parseInt(params.id, 10);
this.form.controls['ID'].setValue(this.id);
this.GetSpeedFenceSettingByFenceId({ FenceId: parseInt(params.id, 10) });
}
});
}
GetSpeedFenceSettingByFenceId(data) {
this.speedFenceService.GetSpeedFenceSettingByFenceId(data).subscribe(
res => {
if (res.State) {
this.form.controls['RuleContent'].setValue({
'MaxSpeed': res.Data.RuleContent.MaxSpeed || '',
'FenceName': res.Data.RuleContent.FenceName || '',
});
}
},
err => { }
);
}
onSubmit(form) {
console.log('此處省略。。。。。');
}
// 取消
back() {
if (this.id) {
this.router.navigate(['../../'], { relativeTo: this.activatedRoute });
} else {
this.router.navigate(['../'], { relativeTo: this.activatedRoute });
}
}
}
總結
多看手冊多動手,才是真理。。
有不足之處或者錯誤之處請留言指出,會及時跟進修正。。謝謝
相關推薦
Angular 2 + 折騰記 :(7) 初步瞭解表單:模板驅動及資料驅動及脫坑要點
前言 表單在整個系統中的作用相當重要,這裡主要扯下響應表單的實現方式。 首先需要操作表單的模組引入這兩個模組; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
Angular 2 + 折騰記 :(1)初識Angular-cli[官方腳手架]及脫坑要點
前言 這個系列的進度有些跳躍性,我儘量直白點解釋,但是我不是官方文件,直入主題!!!! 什麼是Angular-cli 簡言之:就是NG團隊自行維護的一個`腳手架`[內建單元測試及
HTML+CSS專案課2:利用table和表單製作“網易郵箱註冊頁面”
知識點:html文件基本結構、table標籤佈局、表單標籤的使用、img標籤、a標籤、p標籤等常見標籤的使用。 製作網頁效果: 網頁製作思路: 1、將整個網頁分成4部分:3個表格+底部段落文字(3個表格設定同樣的寬度,水平居中,邊框為0等屬性) 2、表格1
Retrofit 2使用要點梳理:淺析POST檔案/表單上傳
實習期的第一個任務就是為專案組預研FACE++智慧人臉識別這一新功能。呼叫曠視FACE++人臉識別介面,進行人臉識別有兩種方式:一是通過先上傳圖片到雲端儲存網站(網盤,雲盤,七牛雲等)獲得圖片檔案對應的URL引數,通過圖片的網路URL引數呼叫FACE++介面;二是在手機客戶端直接上傳檔案呼叫FACE++介
js控制 按enter進行搜索或提交表單:
cti search onkeydown var 點擊 ear win doc all js控制 按enter進行搜索或提交表單://按enter 進行搜索document.onkeydown = function(e){ var ev = document.all
activiti自己定義流程之整合(四):整合自己定義表單部署流程定義
borde row ont 創建 source als dst art select 綜合前幾篇博文內容。我想在整合這一部分中應該會有非常多模塊會跳過不講,就如自己定義表單的表單列表那一塊,由於這些模塊在整合的過程中都差點兒沒有什麽修改,再多講也是反復無用功。
第二章:表單和模板
實際應用 新版 page rms 模板語言 file erl style 模式 在第一章中,我們學習了使用Tornado創建一個Web應用的基礎知識。包括處理函數、HTTP方法以及Tornado框架的總體結構。在這章中,我們將學習一些你在創建Web應用時經常會用到的更強大的
讀書筆記:HTML祕籍Web表單
//一個html5的表單 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title&
VUE:事件處理和表單輸入繫結
事件處理 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>07_事件處理</title> </
VUE:事件處理和表單輸入綁定
點擊 event http def nbsp mode 愛好 gpa method 事件處理 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"
Atitit 面試技術點最小化問題法總結 目錄 1. Web 前端 1 1.1. Jq 常用操作哪些?? 1 1.2. 查詢後如何繫結後端資料到表格 2 1.3. 提交後怎麼接受表單資料 2 2.
Atitit 面試技術點最小化問題法總結 目錄 1. Web 前端 1 1.1. Jq 常用操作哪些?? 1 1.2. 查詢後如何繫結後端資料到表格 2 1.3. 提交後怎麼接受表單資料 2 2. Mvc Springmvc 2 2.1
JSP-實驗:表單傳值-提交表單並傳遞、獲取資料
JSP-實驗:表單傳值-提交表單並傳遞、獲取資料 說明: 參考連結在最後1 我這個版本執行過,反正沒大問題,但是用參考的那個網頁上的內容,就會出錯……原因也寫在後面了。 實驗 實驗內容: 利用表單傳遞資料,此題目包含01.html、01.jsp
JSP-詳細總結form表單:name= method=post(get) action=
(學習語言:JSP) 文章目錄 name="form" method=post (或get) get方法 post方法 對比【表格】 `action="___.jsp"`
使用O2OA二次開發搭建企業辦公平臺(十三)流程開發篇:報銷審批流程表單開發
本部落格為O2OA系列教程、O2OA使用手冊,教程目錄和各章節天梯將在連載完後更新。 使用O2OA二次開發搭建企業辦公平臺(一)平臺部署篇:平臺下載和部署 使用O2OA二次開發搭建企業辦公平臺(二)平臺部署篇:埠衝突和伺服器埠配置 使用O2OA二次開發搭建企業辦公平臺(三)平臺部署篇:使用外部資料庫
element UI表單驗證:一個複雜迴圈表單渲染後資料修改後的部分表單項驗證
一、前言 普通的表單驗證參考element UI官方文件即可找到解決方案並順利進行程式碼實現,官方也給出了幾個示例,是很好的參考。不過,對於複雜的表單驗證,官方文件並沒有給出過多示例或者說明。文章中的例項就是在實際專案中遇到的一個複雜表單的驗證問題。 文章中前端程式碼基
20181022mysql操作一:建立庫,表的增刪改查,資料的增刪改
1、建立資料庫 create database python charset=utf8; 2、使用資料庫 use python; 3、建立表結構 create table student( id int primary key auto_increment
PHP:curl模擬form表單上傳檔案
<form action="" method="post" enctype="multipart/form-data"> <input type="file" name="upload"> <buttion>submit</button> </f
【HTML&CSS】HTML表單:實現互動
瀏覽器通過HTML表單和伺服器實現互動,表單是一個可供使用者輸入資訊的頁面,使用者提交表單後,表單包含的資訊會發送到一個Web伺服器,由伺服器指令碼負責處理並響應,返回一個HTML頁面,最後瀏覽器顯示這個頁面。 表單元素 <form> 所有表單
[Swift通天遁地]二、表格表單-(2)建立右側帶有索引的UITableView(表單檢視)
本文將演示如何給表格新增索引功能。 在專案導航區,開啟檢視控制器的程式碼檔案【ViewController.swift】 現在開始編寫程式碼,建立一個表格,並在表格右側新增一列快捷索引。 1 import UIKit 2 3 //使當前的檢視控制器類,遵循表格的資料來源協議UIT
XHTML/CSS 網頁表單:5種簡單技術
技術1:標籤三明治 將輸入框,選擇框和文字框全部包含進 label 元素,並全部設定為塊級元素。將單選按鈕和多選框顯示方式設定為 inline 以便於它們在同一行出現。如果你比較喜歡 label 和單選按鈕/多選框出現在不同行,可以選擇不把它包含在 label 裡面,或者使用硬換行處理。