控件(input、select、textarea)是用户输入数据的一种方式。Form(表单)是这些控件的集合,目的是将相关的控件进行分组。
表单和控件提供了验证服务,所以用户可以收到无效输入的提示。这提供了更好的用户体验,因为用户可以立即获取到反馈,知道如何修正错误。请记住,虽然客户端验证在提供良好的用户体验中扮演重要的角色,但是它可以很简单地被绕过,因此,客户端验证是不可信的。服务端验证对于一个安全的应用来说仍然是必要的。
一、Simple form
理解双向数据绑定的关键directive是ngModel。ngModel提供了从model到view和view到model的双向数据绑定。并且,它还向其他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">
<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="https://www.jb51.net/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都是必填的,但当它们修改过之后(dirty),背景将呈现红色。这确保用户不会直到与表单交互之后(提交之后?),发现未能满足其有效性,才为一个错误而分心。
<!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">
<form novalidate>
名字: <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="https://www.jb51.net/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的实例。控件实例可以相似地使用name属性暴露在form中。这说明form和控件(control)两者的内部属性对于使用标准绑定实体(standard binding primitives)绑定在视图中的这个做法是可行的。
这允许我们通过以下特性来扩展上面的例子:
RESET按钮仅仅在form发生改变之后才可用。
SAVE按钮仅仅在form发生改变而且输入有效的情况下可用。
为user.email和user.agree定制错误信息。