AngularJS 總結 (Form)
Forms
為了讓form以及控件、ngModel富有樣式,可以增加以下class:
通過在元素上添加repuired等驗證指令 angularjs自動更具狀態切換這些class
-
ng-valid (驗證成功)
-
ng-invalid (驗證失敗)
-
ng-pristine(從未輸入過)
-
ng-dirty(輸入國)
在angular中,表單是FormController的一個實例。表單實例可以隨意地使用name屬性暴露到scope中(只可意會,不可言傳啊。。)
<!DOCTYPE HTML>
<html 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">
<form novalidate name="formName">
名字: <input ng-model="user.name" name="userName" type="text" required><br/>
<div ng-show="formName.userName.$dirty&&formName.userName.$invalid">
<span>請填寫名字</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">請填寫Email</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();
});
</script>
</body>
</html>
custrom Validation
-
Model到View更新 無論什么時候Model發生改變,所有的ngModelController.$formatters(model發生改變時觸發數據有效驗證和格式化轉變)數組中的function將排隊執行,所以在這里每一個function都有機會去格式化model的值,并且通過NgModelController.$setValidity修改空間的驗證狀態。
-
View到Model更新 無論任何時候用戶與控件發生交互,將會觸發NgModelCtroller.$setViewValue。這時候輪到執行NgModelController.$parsers(當控件從dom取值之后,將會執行這個數組中的所有方法,對值進行審查過濾或轉換,也進行驗證)數組中的所有方法。
在下面的例子中我們將創建兩個directive。
-
第一個是integer,它負責驗證輸入到底是不是一個有效的整數。例如1.23是一個非法的值,因為它包含小數部分。注意,我們通過在數組頭部插入(unshift)來代替在尾部插入(push),這因為我們想它首先執行并使用這個控件的值(估計這個Array是當作隊列來使用的),我們需要在轉換發生之前執行驗證函數。
-
第二個directive是smart-float。他將”1.2”和”1,2”轉換為一個合法的浮點數”1.2”。注意,我們在這不可以使用HTML5的input類型”number”,因為瀏覽器不允許用戶輸入我們預期的非法字符,如”1,2”(它只認識”1.2”)。
<!DOCTYPE HTML>
<html 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>
<form novalidate name="formName">
<div>
大小(整數 0 - 10):<input integer type="number" ng-model="size" name="size" min="0" max="10"/>{{size}}{{formName.size.$error.integer}}<br/>
<span ng-show="formName.size.$error.integer">這不是一個有效的整數</span>
<span ng-show="formName.size.$error.min || formName.size.$error.max">
數值必須在0到10之間
</span>
</div>
<div>
長度(浮點數):
<input type="text" ng-model="length" name="length" smart-float/>
{{length}}<br/>
<span ng-show="formName.length.0error.float">這不是一個有效的浮點數</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) {
//View - >Model的更新
ctrl.$parsers.unshift(function (viewValue) {
//model -> view的更新嗎??
//console.log(viewValue, '++');
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);
}else {
ctrl.$setValidity("float", false);
return undefined;
}
});
}
}
});
</script>
</body>
</html>
angular實現了所有HTML的基礎控件(input,select,textarea),能勝任大多數場景。然而,如果我們需要更加靈活,我們可以通過編寫一個directive來實現自定義表單控件的目的。
為了制定控件和ngModel一起工作,并且實現雙向數據綁定,它需要:
-
實現render方法,是負責在執行完并通過所有NgModelController.$formatters方法后,呈現數據的方法。
-
調用$setViewValue方法,無論任何時候用戶與控件發生交互,model需要進行響應的更新。這通常在DOM事件監聽器里實現。
<!DOCTYPE HTML>
<html 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>
<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";
};
});
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() {
//當根scope的model發生改變時 $render觸發(00!)我這么認為
ele.html(scope.content);
};
//讀取初始值
ctrl.$setViewValue(ele.text());
}
};
});
</script>
</body>
</html>
來自:http://my.oschina.net/felumanman/blog/330624