双向数据绑定 ngModelController

[TOC]

注:如果想在input显示一个值,然后实际上是另一个值的话,有多种方法,思路就是element.val()用来显示用于展示的值,model的值可以用

  • ctrl.$parsrs.push(function(value){
    return 这里返回ctrl的值
    })
  • ctrl.$setViewValue()
    -ctrl.$ViewValue=""
    具体看下文

ngModelController

参考官网(需要翻墙)

1、指令的required

假如我们现在需要编写两个指令,在linking函数中有很多重合的方法,为了避免重复自己(著名的DRY原则),我们可以将这个重复的方法写在第三个指令的controller中,然后在另外两个需要的指令中require这个拥有controller字段的指令,最后通过linking函数的第四个参数就可以引用这些重合的方法。代码的结构大致如下:

var app = angular.modeule('myapp',[]);

app.directive('common',function(){
    return {
    ...
    controller: function($scope){
        this.method1 = function(){
        };
        this.method2 = function(){
        };
    },
    ...
    }
});

app.directive('d1',function(){
    return {
    ...
    require: '?^common',
    link: function(scope,elem,attrs,common){
        scope.method1 = common.method1;
        ..
        },
    ...
    }
});

app.directive('d2',function(){
    return {
    ...
    require: '?^common',
    link: function(scope,elem,attrs,common){
        scope.method1 = common.method1;
        ..
        },
    ...
    }
});

所以link的第四个参数就是required的指令对应的ctrl

2 ngModel中的内建属性和方法

先看看例子:

<form name="myForm">
 <div contenteditable
  name="myWidget" ng-model="userContent"
  strip-br="true"
  required>Change me!</div>
  <span ng-show="myForm.myWidget.$error.required">Required!</span>
 <hr>
 <textarea ng-model="userContent"></textarea>
</form>

指令:


angular.module('customControl', [])
    .directive('contenteditable', function() { 
        return { 
            restrict: 'A', // 作为元素属性 
            require: '?ngModel', // 获取ngModelController
            link: function(scope, element, attrs, ngModel) { 
                if(!ngModel) return; // 如果没有ng-model则什么都不做
                 // 指定UI的更新方式
                ngModel.$render = function() {
                  element.html(ngModel.$viewValue || '');
                };

                // 监听change事件来开启绑定
                element.on('blur keyup change', function() {
                  scope.$apply(read);
                });
                read(); // 初始化

                // 将数据写入model
                function read() {
                  var html = element.html();
                  // 当我们清空div时浏览器会留下一个<br>标签
                  // 如果制定了strip-br属性,那么<br>标签会被清空
                  if( attrs.stripBr && html == '<br>' ) {
                    html = '';
                  }
                  ngModel.$setViewValue(html);
                }
             }
        };
    });
    

ngModelController方法

  • $render(); 当视图需要更新的时候会被调用。使用ng-model的指令应该自行实现这个方法。
  • $isEmpty(value);该方法用于判断输入值是否为空。
    例如,使用ngModelController的指令需要判断其中是否有输入值的时候会使用该方法。该方法可用来判断值是否为undefined,'',null或者NaN。 你可以根据自己的需要重载该方法。
  • $setValidity(validationErrorKey, isValid);该方法用于改变验证状态,以及在控制变化的验证标准时通知表格。这个方法应该由一个验证器来调用。例如,一个解析器或者格式化函数。
  • $setPristine();该方法用于设置控制到原始状态。该方法可以移除'ng-dirty'类并将控制恢复到原始状态('ng-pristine'类)。
  • $cancelUpdate();该方法用于取消一次更新并重置输入元素的值以防止$viewCalue发生更新,它会由一个pending debounced事件引发或者是因为input输入框要等待一些未来的事件。
  • $setViewValue(value, trigger)方法 该方法用来更新视图值。这个方法应该在一个视图值发生变化时被调用,一般来说是在一个DOM事件处理函数中。例如,input和select指令就调用了这个函数。
    这个方法将会更新$viewValue属性,然后在$pasers中通将这个值传递给每一个函数,其中包括了验证器。这个值从$parsers输出后,将会被用于$modelValue以及ng-model属性中的表达式。
    最后,所有位于$viewChangeListeners列表中注册的监听器将会被调用。

ngModelController属性

  • $viewValue
    视图中的实际值

  • $modelValue
    model中的值,它金额控制器绑定在一起

  • $parsers

将要执行的函数的数组,无论什么时候控制器从DOM中读取了一个值,它都将作为一个管道。其中的函数依次被调用,并将结果传递给下一个。最后出来的值将会被传递到model中。其中将包括验证和转换值的过程。对于验证步骤,这个解析器将会使用$setValidity方法,对于不合格的值将返回undefined。

  • $formatters

一个包含即将执行函数的数组,无论什么时候model的值发生了变化,它都会作为一个管道。其中的每一个函数都被依次调用,并将结果传递给下一个函数。该函数用于将模型传递给视图的值进行格式化。

  • $viewChangeListeners
    只要视图的值发生变化,其中的函数就会被执行。其中的函数执行并不带参数,它的返回值也会被忽略。它可以被用在额外的#watches中。

  • $error
    一个包含所有error的对象

  • $pristine
    如果用户还没有进行过交互,值是true。

  • $dirty
    如果用户已经进行过交互,值是true。

  • $valid
    如果没有错误,值是true。

  • $invalid
    如果有错误,值是true。

关于双向绑定其他

ng-model-options

ng-model-options,就是可以实现对延迟更新、如何触发更新、时区(timezone针对input[type='date']等)等的控制

//github上的block-example/表单操作-11/ng-model-options.html
angular.module('optionsExample', [])
.controller('ExampleController', ['$scope', function($scope) {
  $scope.user = { name: 'say', data: '' };

  $scope.cancel = function(e) {
    if (e.keyCode == 27) {
      $scope.userForm.userName.$rollbackViewValue();
    }
  };
}]);
<div ng-controller="ExampleController">
  <form name="userForm">
    Name:
    <input type="text" name="userName"
           ng-model="user.name"
           ng-model-options="{ updateOn: 'blur',debounce: 1000 ,getterSetter: false  }"
           ng-keyup="cancel($event)" /><br />

    Other data:
    <input type="text" ng-model="user.data" /><br />
  </form>
  <pre>user.name = <span ng-bind="user.name"></span></pre>
</div>
  • updateOn:可以写入事件名字,将此element按所写事件触发更新

  • debounce:当我们写进keydowm事件的时候,我需要的是它尽可能说是当我输入完毕后,再去触发更新,那么这个时候我们可以延迟个1s!

  • getterSetter:为true的时候,则是指element的值是从函数return过来滴!

FormController的方法:

$rollbackViewValue(); $commitViewValue(); $addControl(); $removeControl(); $setValidity(); $setDirty(); $setPristine(); $setUntouched(); $setSubmitted();
  • $addControl() //添加ngModel controller ,ngModel会自动添加,除非自定义指令或许会用上
  • $removeControl() //与$addControl()相反
  • $setValidity() //在自定义表单检验有着很大作用
  • $rollbackViewValue() //这个我是这样理解的,回滚到上一个ViewValue

属性:

$pristine(form没被动过)  $dirty(form被动过) $valid(全部验证通过) $invalid(验证不通过) $submitted  $error
    email、max、maxlength、min、minlength、number、pattern、required、url、date、datetimelocal、time、week、month

ngModel.NgModelController

ngModel指令提供了API.它不包含任何逻辑处理DOM渲染或DOM event,这样的DOM相关逻辑应使用其他指令,NgModelController用来控制元素的数据绑定
点击查看官方文档
方法:

$render(); $isEmpty(value); $setValidity(validationErrorKey, isValid); $setPristine(); $setDirty(); $setUntouched(); $setTouched(); $rollbackViewValue(); $validate(); $commitViewValue(); $setViewValue(value, trigger);
  • $render: angular 会把 $modelValue 经过 $formatters 得出来的值放入 $viewValue中,(这时 $viewValue = $modelValue 经过 $formatters) 然后触发我们写好的 - - $render . 跟着$setViewValue(value, trigger);一起使用。
  • $setViewValue:scope改变$modelValue,使用$setViewValue(),改变$viewValue
  • $setValidity:使用这个配合$parsers可以实现表单自定义验证

拥有的属性:

$viewValue  //界面显示的数据

$modelValue  //$scope上面的value

$parsers  //在view->model的时候会触发的一个函数组,无论什么时候Model发生改变,所有的ngModelController.$formatters(model发生改变时触发数据有效验证和格式化转变)数组中的function将排队执行,所以在这里每一个function都有机会去格式化model的值,并且通过NgModelController.$setValidity修改空间的验证状态。

$formatters //在model->view的时候会触发的一个函数组, 无论任何时候用户与控件发生交互,将会触发NgModelCtroller.$setViewValue。这时候轮到执行NgModelController.$parsers(当控件从dom取值之后,将会执行这个数组中的所有方法,对值进行审查过滤或转换,也进行验证)数组中的所有方法。

$validators 
$asyncValidators 
$viewChangeListeners 
$error 
$pending 
$untouched 
$touched 
$pristine 
$dirty 
$valid 
$invalid 
$name

双向绑定的机制可以在$parsers和$formatters可以体现出来,通过这些我们可以在view->scope做类似表单验证(自定义)的功能(配合$setValidity(validationErrorKey, isValid);),scope->view数据格式自定义等操作(配合$setViewValue(value, trigger);),可以看一下下面的这个例子:
https://github.com/xiaobin5201314/AngularJS-Learning/blob/master/block-example/表单操作-11/ng-model.html


var custom = angular.module('customControl', ['ngSanitize']);
 custom.directive("noxiaobin", function () {
                 return {
                     restrict: "A",
                     require: "?ngModel",
                     link: function (scope, element, attrs, ngModel) {
                        if (!ngModel) return;
                         ngModel.$parsers.push(function (v) {  //传说中的验证器
 
                                 if (v != "xiaobin") {
                                     ngModel.$setValidity('noxiaobin', true); //通过获取从dom过来的值,然后进行验证,使用$setValidity('noxiaobin', true);改变noxiaobin的值,然后反馈会dom
                                     return v;
                                 } else {
                                     ngModel.$setValidity('noxiaobin', false);
                                     return undefined;
                                 }
 
                         });
                     }
                 }
             });

 custom.directive('contenteditable', ['$sce', function($sce) {
              return {
                restrict: 'A', //指定该指令是为属性类型的指令
                require: '?ngModel', // 与ngModel指令的相互交流
                link: function(scope, element, attrs, ngModel) { //scope分别是指令作用的作用域,element触发指令的元素,attrs是element的属性集合,ngmodel是控制器就是引入的ngModel
                  if (!ngModel) return;

 // output data to the view
                  ngModel.$render = function() {
                     element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));  //$viewValue的值进行format
                  };

 //对element的监听
                  element.on('blur keyup change', function() {
                    scope.$evalAsync(read); //执行read方法
                  });
                  read(); // 初始化

 // Write data to the model
                  function read() {
                    var html = element.html();
                    // When we clear the content editable the browser leaves a <br> behind
                    // If strip-br attribute is provided then we strip this out
                    if ( attrs.stripBr && html == '<br>' ) {
                      html = '';
                    }

 ngModel.$setViewValue(html); //获取ViewValue,设置$viewValue
                  }
                }
              };
            }]);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 指令定义 对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能。  我们可以自己...
    oWSQo阅读 1,176评论 0 0
  • 过滤器用来格式化需要展示给用户的数据。AngularJS有很多实用的内置过滤器,同时也提供了方便的途径可以自己创建...
    oWSQo阅读 1,085评论 0 5
  • 基础ng属性指令 布尔属性 布尔属性代表一个true或false值。当这个属性出现时,这个属性的值就是true(无...
    oWSQo阅读 1,179评论 0 0
  • 如果有一天 我死了 只留下一本书和几首诗 我不知道 书是不是关于爱情 但诗中 必有一百首 和你相关 时间会抹去一切...
    北环路真人阅读 97评论 0 0