angular学习(十一)—— Form

前端之家收集整理的这篇文章主要介绍了angular学习(十一)—— Form前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

转载请写明来源地址:http://www.jb51.cc/article/p-qbxananr-bph.html

form

control主要用于接收用户输入,例如input,select,textarea。而form是一组相关控件的集合。form和control提供验证服务,可以在用户提交表单到后端前得到无效输入的通知

一个简单的form

form的验证要比服务端的验证好很多,因为更加及时得到反馈以便纠正错误。虽然客户端的验证体验很好,但是可以很容易做到规避验证,服务端的验证还是非常必要的,特别是那些安全要求高的应用。

理解angularjs双向绑定的关键点在于指令ngModel,ngModel提供了视图到模型,模型到视图的双向绑定,它还提供了一些api给其他指令,用于增强它的作用。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="formExample"> <div ng-controller="ExampleController"> <form novalidate class="simple-form"> <label>Name: <input type="text" ng-model="user.name" /></label><br /> <label>E-mail: <input type="email" ng-model="user.email" /></label><br /> Best Editor: <label><input type="radio" ng-model="user.preference" value="vi" />vi</label> <label><input type="radio" ng-model="user.preference" value="emacs" />emacs</label><br /> <input type="button" ng-click="reset()" value="Reset" /> <input type="submit" ng-click="update(user)" value="Save" /> </form> <pre>user = {{user | json}}</pre> <pre>master = {{master | json}}</pre> </div> <script> angular.module('formExample',[]) .controller('ExampleController',['$scope',function($scope) { $scope.master = {}; $scope.update = function(user) { $scope.master = angular.copy(user); }; $scope.reset = function() { $scope.user = angular.copy($scope.master); }; $scope.reset(); }]); </script> </body> </html>

注意novalidate可以禁用浏览器对表单进行原生性的校验。
除非输入通过校验,否则ngModel对应的值不会被设置。比如email类型的输入框必须使用user@domain的格式。

使用css class

为了表单和控件一样都有样式,ngModel增加了一些css class:

  • ng-valid:model有效
  • ng-invalid:model无效
  • ng-valid-[key]:通过$setValidity添加的每一个有效的key
  • ng-invalid-[key]:通过$setValidity添加的每一个无效的key
  • ng-pristine:控件值为初始状态
  • ng-dirty:控件的值已经做过了修改
  • ng-touched:控件已经被点击过并失去焦点
  • ng-untouched:控件还未被点击过
  • ng-pending:还有$asyncValidators未完成。

下面的例子使用css来显示控件的输入有效性。在这个例子中,user.name和user.email是必须输入的,但是只有当输入是模糊的时候(控件被点击并失去焦点之后)才会显示红色的背景,这确保了用户只有在和控件交互之后,而输入无法满足验证条件,才会提示错误,而在交换之前说不会提示错误的。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="formExample"> <div ng-controller="ExampleController"> <form novalidate class="css-form"> <label>Name: <input type="text" ng-model="user.name" required /></label><br /> <label>E-mail: <input type="email" ng-model="user.email" required /></label><br /> Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label> <label><input type="radio" ng-model="user.gender" value="female" />female</label><br /> <input type="button" ng-click="reset()" value="Reset" /> <input type="submit" ng-click="update(user)" value="Save" /> </form> <pre>user = {{user | json}}</pre> <pre>master = {{master | json}}</pre> </div> <style type="text/css"> .css-form input.ng-invalid.ng-touched { background-color: #FA787E; } .css-form input.ng-valid.ng-touched { background-color: #78FA89; } </style> <script> angular.module('formExample',function($scope) { $scope.master = {}; $scope.update = function(user) { $scope.master = angular.copy(user); }; $scope.reset = function() { $scope.user = angular.copy($scope.master); }; $scope.reset(); }]); </script> </body> </html>

form和control的状态绑定

在angualr中,form是FormController的实例,form实例可以通过name属性发布到scope中。同样,带有ngModel指令的输入控件一样也是NgModelController实例,一样可以通过控件的name属性发布,作为form实例的一个属性
这意味着form和控件的内部状态一样可以通过标准的绑定方式在视图中绑定。

我们来扩展一下上面的例子:

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="formExample"> <div ng-controller="ExampleController"> <form novalidate class="css-form" name="form"> <label>Name: <input type="text" ng-model="user.name" name="uName" required="" /></label><br /> <div ng-show="form.$submitted || form.uName.$touched"> <div ng-show="form.uName.$error.required">Tell us your name.</div> </div> <label>E-mail: <input type="email" ng-model="user.email" name="uEmail" required /></label><br /> <div ng-show="form.$submitted || form.uEmail.$touched"> <span ng-show="form.uEmail.$error.required">Tell us your email.</span> <span ng-show="form.uEmail.$error.email">This is not a valid email.</span> </div> Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label> <label><input type="radio" ng-model="user.gender" value="female" />female</label><br /> <label> <input type="checkBox" ng-model="user.agree" name="userAgree" required="" /> I agree: </label> <input ng-show="user.agree" type="text" ng-model="user.agreeSign" required="" /> <br /> <div ng-show="form.$submitted || form.userAgree.$touched"> <div ng-show="!user.agree || !user.agreeSign">Please agree and sign.</div> </div> <input type="button" ng-click="reset(form)" value="Reset" /> <input type="submit" ng-click="update(user)" value="Save" /> </form> <pre>user = {{user | json}}</pre> <pre>master = {{master | json}}</pre> </div> <style type="text/css"> .css-form input.ng-invalid.ng-touched { background-color: #FA787E; } .css-form input.ng-valid.ng-touched { background-color: #78FA89; } </style> <script> angular.module('formExample',function($scope) { $scope.master = {}; $scope.update = function(user) { $scope.master = angular.copy(user); }; $scope.reset = function(form) { if (form) { form.$setPristine(); form.$setUntouched(); } $scope.user = angular.copy($scope.master); }; $scope.reset(); }]); </script> </body> </html>

自定义model更新触发器

默认情况下,对内容对任何更改都会触发model的改变和表单的验证。你可以通过ngModelOptions指令绑定到特殊的事件列表中以重写这种行为。ng-model-options="{ updateOn: 'blur' }"表示仅仅在用户输入并且失去焦点时才会更新model并且进行表单验证。如果是多个事件,可以使用空格分开,例如:ng-model-options="{ updateOn: 'mousedown blur' }"

如果想保留默认的行为,而只是在默认事件上添加新的事件可以触发更新和验证,那么只需添加default作为一个普通的事件之一。
ng-model-options="{ updateOn: 'default blur' }"

下面是个重写立即更新对例子。只有在用户和输入框产生交互时(点击控件并且失去焦点时),输入框的更改才会更新到model中。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <script> angular.module('customTriggerExample',function($scope) { $scope.user = {name:"aa"}; }]); </script> <body ng-app="customTriggerExample"> <div ng-controller="ExampleController"> <form> <label>Name: <input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" /></label><br /> <label> Other data: <input type="text" ng-model="user.data" /></label><br /> </form> <pre>username = "{{user.name}}"</pre> <pre>userdata = "{{user.data}}"</pre> </div> </body> </html>

延时model更新

你也可以通过ngModelOptions指令的debounce键延时更新和验证。这个延迟对于解析器,验证器和model的标签$dirty或$pristine.)同样起作用。

ng-model-options="{ debounce: 500 }"表示将最后一次内容的改变触发model更新和form验证之前要等上500毫秒。

如果使用了自定义的触发器,那么使用debounce对象对每一个事件加上自定义的消抖超时时间。这在某些特定情况下还是有用的,比如blur事件后需要立即更新和验证。语法如下:
ng-model-options="{ updateOn: 'default blur',debounce: { default: 500,blur: 0 } }"

注意,如果这些属性添加到某个元素中,那么这个元素的所有子元素和控件都会继承他的设定,除非子元素和控件重写这些属性

下面的例子演示的是model更改的消抖,model将会在内容最后一次更改250毫米后进行更新。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <script> angular.module('debounceExample',function($scope) { $scope.user = {}; }]); </script> <body ng-app="debounceExample"> <div ng-controller="ExampleController"> <form> <label>Name: <input type="text" ng-model="user.name" ng-model-options="{ debounce: 250 }" /></label><br /> </form> <pre>username = "{{user.name}}"</pre> </div> </body> </html>

自定义验证

AngularJS为html5最常用的输入类型(text,number,url,email,date,radio,checkBox)提供了基本的实现,以及一些用于验证的指令(required,pattern,minlength,maxlength,min,max)。

如果想自定义验证的指令,你需要在ngModelController实例的$validators对象中增加自定义的验证函数。可以参照下面的例子。

$validators对象的每一个验证函数都有两个参数modelValue和viewValue,angularjs会在内部调用$setValidity函数,参数就是这个验证函数的返回值。每次输入发生变化($setViewValue被调用)或约束模型发生变化时,验证函数都会执行。 parsers formatters成功运行之后,验证会分别进行。如果验证失败,错误的key会保存在ngModelController.$error中。

此外,$asyncValidators对象处理异步的验证,比如需要通过http到后台请求验证数据的情况。添加到这个对象的验证函数必须返回一个promise,在有效时候resolve,无效时候reject。在异步验证的过程中,验证的key会被保存到ngModelController.$pending中。

下面的例子创建了两个验证指令:

  • integer指令验证输入是否是一个整数。例如,1.33就是个无效值。注意我们验证的事viewValue,控件中输入的值,而不是modleValue,这是因为类型为number的输入框会通过$parsers将viewValue转化为数字,如果我们输入的事1.00,那么modelValue将会是1,而viewValue是1.00,显然是无效的

  • username指令,异步检查用户输入的值是否已经存在,我们用$q.defer()来模拟服务器请求。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="form-example1"> <form name="form" class="css-form" novalidate> <div> <label> Size (integer 0 - 10): <input type="number" ng-model="size" name="size" min="0" max="10" integer />{{size}}</label><br /> <span ng-show="form.size.$error.integer">The value is not a valid integer!</span> <span ng-show="form.size.$error.min || form.size.$error.max"> The value must be in range 0 to 10!</span> <span ng-show="form.size.$error.require">111</span> </div> <div> <label> Username: <input type="text" ng-model="name" name="name" username />{{name}}</label><br /> <span ng-show="form.name.$pending.username">Checking if this name is available...</span> <span ng-show="form.name.$error.username">This username is already taken!</span> </div> </form> </body> <script> var app = angular.module('form-example1',[]); var INTEGER_REGEXP = /^-?\d+$/; app.directive('integer',function() { return { require: 'ngModel',link: function(scope,elm,attrs,ctrl) { ctrl.$validators.integer = function(modelValue,viewValue) { if (ctrl.$isEmpty(modelValue)) { // consider empty models to be valid return true; } if (INTEGER_REGEXP.test(viewValue)) { // it is valid return true; } // it is invalid return false; }; } }; }); app.directive('username',function($q,$timeout) { return { require: 'ngModel',ctrl) { var usernames = ['Jim','John','Jill','Jackie']; ctrl.$asyncValidators.username = function(modelValue,viewValue) { if (ctrl.$isEmpty(modelValue)) { // consider empty model valid return $q.resolve(); } var def = $q.defer(); $timeout(function() { // Mock a delayed response if (usernames.indexOf(modelValue) === -1) { // The username is available def.resolve(); } else { def.reject(); } },2000); return def.promise; }; } }; }); </script> </html>

修改内置验证

angularjs有一些内置的验证器,你可以很容易的移除或替换这些验证器。下面的例子演示了如何重写类型为email的验证器。

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="form-example-modify-validators"> <form name="form" class="css-form" novalidate> <div> <label> Overwritten Email: <input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" /> </label> <span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br> Model: {{myEmail}} </div> </form> </body> <script> var app = angular.module('form-example-modify-validators',[]); app.directive('overwriteEmail',function() { var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i; return { require: 'ngModel',ctrl) { // 指定了ngModel,并且输入类型为email if (ctrl && ctrl.$validators.email) { // 重写angularjs的内置email验证器 ctrl.$validators.email = function(modelValue) { return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue); }; } } }; }); </script> </html>

自定义form控件

angularjs实现了所有的html基本控件(input,textarea),大多数情况下足够用了,但是如果你需要更多的灵活性,你可以自定义form控件。

为了让自定义的控件可以支持ngModel,并且带有双向绑定,需要这样做:

  • 实现$render方法,在NgModelController.$formatters之后它负责对数据进行渲染
  • 用户和控件交互之后,模型需要更新时,调用$setViewValue方法。通常是由DOM的事件监听器做的。

可以看下下面这个例子:

<!DOCTYPE html> <html> <head> <Meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <body ng-app="form-example2"> <div contentEditable="true" ng-model="content" title="Click to edit">Some</div> <pre>model = {{content}}</pre> <style type="text/css"> div[contentEditable] { cursor: pointer; background-color: #D0D0D0; } </style> </body> <script> angular.module('form-example2',[]).directive('contenteditable',ctrl) { // view -> model elm.on('blur',function() { ctrl.$setViewValue(elm.html()); }); // model -> view ctrl.$render = function() { elm.html(ctrl.$viewValue); }; // load init value from DOM ctrl.$setViewValue(elm.html()); } }; }); </script> </html>





如果我的文章对您有帮助,请用支付宝打赏:

猜你在找的Angularjs相关文章