首页 > 网站 > WEB开发 > 正文

form 和 ngModel

2024-04-27 14:20:18
字体:
来源:转载
供稿:网友

form 和 ngModel

参考

https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

https://docs.angularjs.org/api/ng/type/form.FormController

angular 提供了表单指令,它和ngModel 经常一起工作,所以一起介绍。

我们先来了解一下基本的ng-model

ng-model 作用是double binding

ng-model 在不同的element上会有不同的同步模式,这些angular已经帮我封装了许多.

当然 angular 也提供了一些方法在 ngModel 这个指令的 controller中(名为 ngModel),使得我们可以在自己的控件 (e.g. : checkBoxList, dropDownList) 也做double binding

此外 ng-model 还有一些基本 option 可以设置(1.3才有)

<input type="text" name="userName"           ng-model="user.name"           ng-model-options="{ updateOn: 'blur', debounce: 1000 ,getterSetter: true  }"/><br />
<PRe>user.name = <span ng-bind="user.name()"></span></pre>

updateOn 写入一个事件名来表示我们希望什么事件促使这个elem被更新,比如 blur / keyup 等

debounce 是deley update 毫秒, 一般我们不希望用户联系每一次keydown时都更新,而是等到用户停止输入时才执行一次更新。就可以放一个delay 实现了

getterSetter = true 可以用在依赖属性上,比如我们的$scope.name = function (){ retrun xx; } 当name是个方法的时候

我们再来看看 ng-model controller 还有些什么属性方法

ngModel controller

                     var ngModelController = {                         "$viewValue": "12", //界面显示的数据                         "$modelValue": "12", //$scope的value                         "$parsers": [null, null], //这里的null是因为json无法看到,是 function 来的                         "$formatters": [null, null],                         "$viewChangeListeners": [null],                          "$pristine": false,                         "$dirty": true,                         "$valid": true,                         "$invalid": false,                         "$name": "name",                          "$error": {                             "required": false, //这里是true代表有error , valid fail                             "minlength": false                         },                         "$$validityState": {} //私有属性不详                      }

$parsers, $formatters 是数据拦截

每一次view to scope 时,会触发$parsers里所有的方法, 我们可以在方法中对数据做一些处理,比如验证或者装换. $formatters 则是 scope to view 时触发

$viewChangeListeners 官网的说明是

Array of functions to execute whenever the view value has changed. 每一次view value change 触发

It is called with no arguments, and its return value is ignored. //no para , no return

This can be used in place of additional $watches against the model value. //用途不是很明白

$dirty , $valid 等,都是配合表单使用的,表单会对这个值总一些统计的工作。

还有一些方法 :

"$render", "$isEmpty","$setValidity", //常用的应该是这个, para(验证指令, isValid)"$setPristine","$setViewValue"

$render 和 $setViewValue 是我们做控件时一定要厉害的。

$render 是一个被angular调用的方法,由我们来告诉angular如何渲染页面。

当 digest 发现scope value changed , angular 会把 $modelValue 经过 $formatters 得出来的值放入 $viewValue中,(这时 $viewValue = $modelValue 经过 $formatters) 然后触发我们写好的 $render .

所以我们在 $render 里面就获取 $viewValue 来写入dom .

$setViewValue 则相反,它是angular写好的方法,我们来调用它,当dom 触发change 或 blur 等事件时,我们获取了value, 我们就调用这个 $setViewValue .

第一步 angular 会 $viewValue = newValue, 然后把经过 $parsers 得到的值 写入 $modelValue 和 scope value .

外传 :

题外话 , 框架和库的区别,库里有很多别人的方法,我们负责写过程,间中调用库里的方法 。框架呢则相反,我们写很多方法告诉,过程则是框架定义好的,它在执行过程时会调用我们写的方法。(忘记从哪里看到的,这让我领悟很多,特别分享一下).

$setValidity 是用于和表单验证通讯的 .

这里给一个自定义验证指令的例子

    <div ng-app="app" ng-controller="email">        <div ng-form="emailForm">            <input type="text" name="email" ng-model="email" is-abc />            <span ng-click="see()">{{ emailForm.$valid }}</span>        </div>    </div>        angular.module("app", []).             directive("isAbc", ["$timeout", function ($timeout) {                 return {                     restrict: "A",                     require: "ngModel",                     link: function ($scope, $element, $attrs, $ctrl) {                         var validator = function (v) {                             $timeout.cancel($ctrl.timeout);                             $ctrl.timeout = $timeout(function () {                                 if (v == "abc") {                                     $ctrl.$setValidity('isAbc', true);                                     return v;                                 } else {                                     $ctrl.$setValidity('isAbc', false);                                     return undefined;                                 }                             }, 2000);                         }                         $ctrl.$parsers.push(validator);                     }                 }             }]);

这里我们创建了一个 is-abc 指令,我们拦截了ngModel,添加了验证手法,通过 $setValidity 通知 form , 这里还做了一个延迟验证的手法。

ng-form || form 指令

ng-form 和 form 是一样的,controller 名字是 form

    <div ng-app="app" ng-controller="email">        <form name="emailForm">            <input type="text" name="email" ng-model="email" required />            <input type="text" name="name" ng-model="email" required ng-minlength="2" />            <span ng-click="see()">{{ emailForm.$valid }}</span>        </form>    </div>

form 有一些规范,一定要有name , 里面的控件也都要有 name , 最好都用ng-model沟通,因为angular封装了自动添加controller 等等的事儿 .

流程大致上是这样,

form -> model -> 验证指令

指令通过拦截model做验证等,通过model告知form

form controller 有一些属性

                     var formController = {                         "$name": "emailForm",                         "$dirty": false, //form被动过                         "$pristine": true, //form没人动过                         "$valid": false, //全部验证pass                         "$invalid": true, //有fail的                         "email": {}, //key是form里头的控件nama,value是 控件 ngModel controller 对象,                         "$error": {"required" : []} //key 是 error 指令名字,value是一个数组,里面是invalid控件的 ngModel controller对象                      }

主要是收录了表单内控件的 ng-model controller 引用

form 中的方法

"$addControl", //添加ngModel controller ,ngModel会自动添加,除非自定义指令或许会用上 "$removeControl", "$setValidity", para(验证指令, isValid, ngModel controller) set ngModel的valid "$setDirty", no para , set属性 "$setPristine"no para , set属性

调用angular 提供的方法,它们会让form model parent等串联起来 .

更新 : 2015-05-23

在1.3版本后我们对 ngModel 的验证比较轻松了,ngModel.$asyncValidators or ngModel.Validators 来输入我们要的验证方法.

ngModel 嵌套的情况,有时候可能指令会嵌套,导致ngModel也嵌套了,有些人可能会直接这样写

scope : {

  ngModel : "="

}

表面上你看这样只是没有问题的,因为angular确实会帮你同步这个值,但是这样写的话,父层的$parsers是不会被触发的。

正确的做法是在子层通过 $render 和 $setViewValue 来修改父层的 ngModel


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表