AngularJs Forms詳解及簡單示例
控件(input、select、textarea)是用戶輸入數(shù)據(jù)的一種方式。Form(表單)是這些控件的集合,目的是將相關(guān)的控件進行分組。
表單和控件提供了驗證服務(wù),所以用戶可以收到無效輸入的提示。這提供了更好的用戶體驗,因為用戶可以立即獲取到反饋,知道如何修正錯誤。請記住,雖然客戶端驗證在提供良好的用戶體驗中扮演重要的角色,但是它可以很簡單地被繞過,因此,客戶端驗證是不可信的。服務(wù)端驗證對于一個安全的應(yīng)用來說仍然是必要的。
一、Simple form
理解雙向數(shù)據(jù)綁定的關(guān)鍵directive是ngModel。ngModel提供了從model到view和view到model的雙向數(shù)據(jù)綁定。并且,它還向其他directive提供API,增強它們的行為。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="SimpleForm">
<head>
<meta charset="UTF-8">
<title>PropertyEvaluation</title>
<style type="text/css">
.ng-cloak {
display: none;
}
</style>
</head>
<body>
<div ng-controller="MyCtrl" class="ng-cloak">
<form novalidate>
名字: <input ng-model="user.name" type="text"><br/>
Email: <input ng-model="user.email" type="email"><br/>
性別: <input value="男" ng-model="user.gender" type="radio">男
<input value="女" ng-model="user.gender" type="radio">女
<br/>
<button ng-click="reset()">還原上次保存</button>
<button ng-click="update(user)">保存</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>saved = {{saved | json}}</pre>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("SimpleForm", []);
app.controller("MyCtrl", function ($scope,$window) {
$scope.saved = {};
$scope.update = function(user) {
$scope.saved = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.saved);
};
$scope.reset();
//不合法的值將不會進入user
});
</script>
</body>
</html>
二、Using CSS classes
為了讓form以及控件、ngModel富有樣式,可以增加以下class:
- ng-valid
- ng-invalid
- ng-pristine(從未輸入過)
- ng-dirty(輸入過)
下面的例子,使用CSS去顯示每個表單控件的有效性。例子中,user.name和user.email都是必填的,但當(dāng)它們修改過之后(dirty),背景將呈現(xiàn)紅色。這確保用戶不會直到與表單交互之后(提交之后?),發(fā)現(xiàn)未能滿足其有效性,才為一個錯誤而分心。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="CSSClasses">
<head>
<meta charset="UTF-8">
<title>CSSClasses</title>
<style type="text/css">
.ng-cloak {
display: none;
}
.css-form input.ng-invalid.ng-dirty {
background-color: #fa787e;
}
.css-form input.ng-valid.ng-dirty {
background-color: #78fa89;
}
</style>
</head>
<body>
<div ng-controller="MyCtrl" class="ng-cloak">
<form novalidate class="css-form" name="formName">
名字: <input ng-model="user.name" type="text" required><br/>
Email: <input ng-model="user.email" type="email" required><br/>
性別: <input value="男" ng-model="user.gender" type="radio">男
<input value="女" ng-model="user.gender" type="radio">女
<br/>
<button ng-click="reset()">RESET</button>
<button ng-click="update(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>saved = {{saved | json}}</pre>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("CSSClasses", []);
app.controller("MyCtrl", function ($scope,$window) {
$scope.saved = {};
$scope.update = function(user) {
$scope.saved = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.saved);
};
$scope.reset();
//不合法的值將不會進入user
});
</script>
</body>
</html>
三、Binding to form and control state
在angular中,表單是FormController的一個實例。表單實例可以隨意地使用name屬性暴露到scope中(這里沒看懂,scope里面沒有一個跟form的name屬性一直的property,但由于有“document.表單名”這種方式,所以還是可以獲取到的)。相似地,控件是NgModelController的實例??丶嵗梢韵嗨频厥褂胣ame屬性暴露在form中。這說明form和控件(control)兩者的內(nèi)部屬性對于使用標準綁定實體(standard binding primitives)綁定在視圖中的這個做法是可行的。
這允許我們通過以下特性來擴展上面的例子:
- RESET按鈕僅僅在form發(fā)生改變之后才可用。
- SAVE按鈕僅僅在form發(fā)生改變而且輸入有效的情況下可用。
- 為user.email和user.agree定制錯誤信息。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="ControlState">
<head>
<meta charset="UTF-8">
<title>ControlState</title>
<style type="text/css">
.ng-cloak {
display: none;
}
.css-form input.ng-invalid.ng-dirty {
background-color: #fa787e;
}
.css-form input.ng-valid.ng-dirty {
background-color: #78fa89;
}
</style>
</head>
<body>
<div ng-controller="MyCtrl" class="ng-cloak">
<form novalidate class="css-form" name="formName">
名字: <input ng-model="user.name" name="userName" type="text" required><br/>
<div ng-show="formName.userName.$dirty&&formName.userName.$invalid">
<span>請?zhí)顚懨?lt;/span>
</div>
Email: <input ng-model="user.email" name="userEmail" type="email" required><br/>
<div ng-show="formName.userEmail.$dirty && formName.userEmail.$invalid">提示:
<span ng-show="formName.userEmail.$error.required">請?zhí)顚慐mail</span>
<span ng-show="formName.userEmail.$error.email">這不是一個有效的Email</span>
</div>
性別: <input value="男" ng-model="user.gender" type="radio">男
<input value="女" ng-model="user.gender" type="radio">女
<br/>
<input type="checkbox" ng-model="user.agree" name="userAgree" required/>我同意:
<input type="text" ng-show="user.agree" ng-model="user.agreeSign" required/>
<br/>
<div ng-show="!formName.userAgree || !user.agreeSign">請同意并簽名~</div>
<button ng-click="reset()" ng-disabled="isUnchanged(user)">RESET</button>
<button ng-click="update(user)" ng-disabled="formName.$invalid || isUnchanged(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>saved = {{saved | json}}</pre>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("ControlState", []);
app.controller("MyCtrl", function ($scope,$window) {
$scope.saved = {};
$scope.update = function(user) {
$scope.saved = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.saved);
};
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.saved);
};
$scope.reset();
//不合法的值將不會進入user
});
</script>
</body>
</html>
四、Custom Validation
angular為大多數(shù)公共的HTML表單域(input,text,number,url,email,radio,checkbox)類型提供了實現(xiàn),也有一些為了表單驗證的directive(required,pattern,,inlength,maxlength,min,max)。
可以通過定義增加定制驗證函數(shù)到ngModel controller(這里是連在一起的ngModelController嗎?)中的directive來定義我們自己的驗證插件。為了得到一個controller,directive如下面的例子那樣指定了依賴(directive定義對象中的require屬性)。
Model到View更新 - 無論什么時候Model發(fā)生改變,所有在ngModelController.$formatters(當(dāng)model發(fā)生改變時觸發(fā)數(shù)據(jù)有效性驗證和格式化轉(zhuǎn)換)數(shù)組中的function將排隊執(zhí)行,所以在這里的每一個function都有機會去格式化model的值,并且通過NgModelController.$setValidity(http://code.angularjs.org/1.0.2/docs/api/ng.directive:ngModel.NgModelController#$setValidity)修改控件的驗證狀態(tài)。
View到Model更新 - 一個相似的方式,無論任何時候,用戶與一個控件發(fā)生交互,將會觸發(fā)NgModelController.$setViewValue。這時候輪到執(zhí)行NgModelController$parsers(當(dāng)控件從DOM中取得值之后,將會執(zhí)行這個數(shù)組中所有的方法,對值進行審查過濾或轉(zhuǎn)換,也進行驗證)數(shù)組中的所有方法。
在下面的例子中我們將創(chuàng)建兩個directive。
第一個是integer,它負責(zé)驗證輸入到底是不是一個有效的整數(shù)。例如1.23是一個非法的值,因為它包含小數(shù)部分。注意,我們通過在數(shù)組頭部插入(unshift)來代替在尾部插入(push),這因為我們想它首先執(zhí)行并使用這個控件的值(估計這個Array是當(dāng)作隊列來使用的),我們需要在轉(zhuǎn)換發(fā)生之前執(zhí)行驗證函數(shù)。
第二個directive是smart-float。他將”1.2”和”1,2”轉(zhuǎn)換為一個合法的浮點數(shù)”1.2”。注意,我們在這不可以使用HTML5的input類型”number”,因為瀏覽器不允許用戶輸入我們預(yù)期的非法字符,如”1,2”(它只認識”1.2”)。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="CustomValidation">
<head>
<meta charset="UTF-8">
<title>CustomValidation</title>
<style type="text/css">
.ng-cloak {
display: none;
}
.css-form input.ng-invalid.ng-dirty {
background-color: #fa787e;
}
.css-form input.ng-valid.ng-dirty {
background-color: #78fa89;
}
</style>
</head>
<body>
<div class="ng-cloak">
<form novalidate class="css-form" name="formName">
<div>
大小(整數(shù) 0 - 10):<input integer type="number" ng-model="size" name="size" min="0" max="10"/>{{size}}<br/>
<span ng-show="formName.size.$error.integer">這不是一個有效的整數(shù)</span>
<span ng-show="formName.size.$error.min || formName.size.$error.max">
數(shù)值必須在0到10之間
</span>
</div>
<div>
長度(浮點數(shù)):
<input type="text" ng-model="length" name="length" smart-float/>
{{length}}<br/>
<span ng-show="formName.length.0error.float">這不是一個有效的浮點數(shù)</span>
</div>
</form>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("CustomValidation", []);
var INTEGER_REGEXP = /^\-?\d*$/;
app.directive("integer", function () {
return {
require:"ngModel",//NgModelController
link:function(scope,ele,attrs,ctrl) {
ctrl.$parsers.unshift(function (viewValue) {//$parsers,View到Model的更新
if(INTEGER_REGEXP.test(viewValue)) {
//合格放心肉
ctrl.$setValidity("integer", true);
return viewValue;
}else {
//私宰肉……
ctrl.$setValidity("integer", false);
return undefined;
}
});
}
};
});
var FLOAT_REGEXP = /^\-?\d+(?:[.,]\d+)?$/;
app.directive("smartFloat", function () {
return {
require:"ngModel",
link:function(scope,ele,attrs,ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if(FLOAT_REGEXP.test(viewValue)) {
ctrl.$setValidity("float", true);
return parseFloat(viewValue.replace(",", "."));
}else {
ctrl.$setValidity("float", false);
return undefined;
}
});
}
}
});
</script>
</body>
</html>
五、Implementing custom form control (using ngModel)
angular實現(xiàn)了所有HTML的基礎(chǔ)控件(input,select,textarea),能勝任大多數(shù)場景。然而,如果我們需要更加靈活,我們可以通過編寫一個directive來實現(xiàn)自定義表單控件的目的。
為了制定控件和ngModel一起工作,并且實現(xiàn)雙向數(shù)據(jù)綁定,它需要:
實現(xiàn)render方法,是負責(zé)在執(zhí)行完并通過所有NgModelController.$formatters方法后,呈現(xiàn)數(shù)據(jù)的方法。
調(diào)用$setViewValue方法,無論任何時候用戶與控件發(fā)生交互,model需要進行響應(yīng)的更新。這通常在DOM事件監(jiān)聽器里實現(xiàn)。
可以查看$compileProvider.directive獲取更多信息。
下面的例子展示如何添加雙向數(shù)據(jù)綁定特性到可以編輯的元素中。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="CustomControl">
<head>
<meta charset="UTF-8">
<title>CustomControl</title>
<style type="text/css">
.ng-cloak {
display: none;
}
div[contenteditable] {
cursor: pointer;
background-color: #D0D0D0;
}
</style>
</head>
<body ng-controller="MyCtrl">
<div class="ng-cloak">
<div contenteditable="true" ng-model="content" title="點擊后編輯">My Little Dada</div>
<pre>model = {{content}}</pre>
<button ng-click="reset()">reset model tirgger model to view($render)</button>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("CustomControl", []);
app.controller("MyCtrl", function ($scope) {
$scope.reset = function() {
$scope.content = "My Little Dada";
//在這里如何獲取NgModelController呢?如果你們知道,希望可以指點指點!謝謝
};
});
app.directive("contenteditable", function () {
return {
require:"ngModel",
link:function (scope, ele, attrs, ctrl) {
//view -> model
ele.bind("blur keyup",function() {
scope.$apply(function() {
console.log("setViewValue");
ctrl.$setViewValue(ele.text());
});
});
//model -> view
ctrl.$render = function(value) {
console.log("render");
ele.html(value);
};
//讀取初始值
ctrl.$setViewValue(ele.text());
}
};
});
</script>
</body>
</html>
- AngularJs Managing Service Dependencies詳解
- AngularJs Injecting Services Into Controllers詳解
- AngularJs Creating Services詳解及示例代碼
- AngularJs Using $location詳解及示例代碼
- AngularJs Understanding Angular Templates
- AngularJs E2E Testing 詳解
- AngularJs Understanding the Controller Component
- AngularJs Understanding the Model Component
- AngularJs Dependency Injection(DI,依賴注入)
- AngularJs Scope詳解及示例代碼
- AngularJs Modules詳解及示例代碼
- AngularJs IE Compatibility 兼容老版本IE
- AngularJs 國際化(I18n/L10n)詳解
- AngularJs directive詳解及示例代碼
- AngularJs unit-testing(單元測試)詳解
相關(guān)文章
關(guān)于angular引入ng-zorro的問題淺析
這篇文章主要給大家介紹了關(guān)于angular引入ng-zorro的問題,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Angular實現(xiàn)的敏感文字自動過濾與提示功能示例
這篇文章主要介紹了Angular實現(xiàn)的敏感文字自動過濾與提示功能,結(jié)合實例形式分析了AngularJS針對字符串的輸入判定及實時顯示相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
詳解Angular之constructor和ngOnInit差異及適用場景
這篇文章主要介紹了詳解Angular之constructor和ngOnInit差異及適用場景的相關(guān)資料,有興趣的可以了解一下2017-06-06
AngularJS模態(tài)框模板ngDialog的使用詳解
這篇文章主要介紹了AngularJS模態(tài)框模板ngDialog的使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05

