ngModel使用说明小demo

第一个点,要了解下:

  • DOM value

  • $viewValue

  • $modelValue

  • scope上挂载的属性的值

平常有2个流程:

  1. $viewValue -->> $modelValue -->> scope 上挂载的属性的值

  2. scope上挂载的属性的值 -->> $modelValue -->> $viewValue

ngModel经常运用的场景就是假如你运用第三方的插件比方时刻插件,每次挑选时刻后都是更新DOM value的值,这个时刻DOM value上的值事实上是你须要绑定到scope属性上的值。那末这个时刻就须要ngModelController

在第一个流程当中,比方我加载了一个时刻插件:pikaday

    html:
    
    <div class="container" ng-controller="demoCtrl">
        <p>挑选的时刻为: {{date.from}}</p>
        <time-picker
            ng-model="date.from"
            ></time-picker>
    </div>
    
    js:
    
    angular.module('demoApp', []).controller('demoCtrl', function($scope) {
        $scope.date = {
            from: ''
        };
        
        $scope.$watch('date.from', function(val) {
            console.log(val);
        });
        
    })
        .directive('testDirective', ['$timeout', function($timeout) {
        return {
            restrict: 'EA',
            require: '?ngModel',
            link: function(scope, ele, attrs, ngModel) {
            template: '<input type="text" id="pikadayTimerPicker">',
            link: function (scope, ele, attr, ngModel) {
                var picker = new Pikaday({
                    field: $('#pikadayTimerPicker')[0],
                    firstDay: 0,
                    yearRange: [2000, 2020],
                    format: 'YYYY-MM-DD',
                    hours24format : false,
                    showTime : true,
                     splitTimeView : true,
                     showSeconds : true,
                     minutesStep : 5,
                    i18n: {
                        previousMonth : '上月',
                        nextMonth     : '下月',
                        months        : ['一月','二月','三月','四月','五月','六月','七月','八月','玄月','十月','十一月','十二月'],
                        weekdays      : ['周日','周一','周二','周三','周四','周五','周六'],
                        weekdaysShort : ['日','一','二','三','四','五','六']
                    },
                    onSelect: function () {
                        if(!ngModel) return; //假如ngModel不存在
                        ngModel.$setViewValue(this._d);
                    }
                });
            }
            }
        }
        })

onSelect回调事宜内里,挪用了ngModel.$setViewValue要领,它的作用就是使DOM value –>> $viewValue –>> $modelValue –>> scope上绑定的属性.

第二个流程当中,比方你须要初始化一个时刻,这个时刻多是从你背景调过来的,或者是猎取的当地的时刻.那末你起首要绑定scope上的属性值,然则这个时刻在时刻插件上面显现的时刻并非scope上绑定的属性值,这个时刻就须要$render要领了:

    
    $scope.data.from = $filter(new Date().valueOf())('YYYY-MM-DD hh:mm:ss');


    xxxxx
        var picker = new Picker({ xxxx });
        
        //这个处所挪用
        ngModel.$render = function() {
            $('#pikadayTimerPicker').val(ngModel.$viewValue);
        }
    xxxxx

这里实行的流程就是:
scope上绑定的属性值发生变化 –>> &dollar;modelValue –>> &dollar;viewValue –>> 挪用&dollar;(‘#pikadayTimerPicker’).val(ngModel.$viewValue)去更新DOM value.

在2个流程当中还应该注重一些处所:

第一个流程当中会经由&dollar;parsers, &dollar;validators2个管道。
第二个流程当中会经由&dollar;formatters,&dollar;render, &dollar;validators 3个管道。

关于&dollar;parses, &dollar;formatters , $validators 3个管道的用法会在下一篇内里讲。

这里着重讲一下源码里的$render要领(文档23189行),

    ctrl.$render = function() {
    // Workaround for Firefox validation #12102.
    var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
    if (element.val() !== value) {
      element.val(value);
    }
  };

这里就是起首推断$viewValue是不是为空,然后再推断当前元素的DOM Value$viewValue是不是一样,再挑选是不是更新视图。

别的就是须要注重的一个处所(文档26947行):

    $scope.$watch(function ngModelWatch() {
    var modelValue = ngModelGet($scope); //猎取scope上绑定的ng-model的值
    
    // if scope model value and ngModel value are out of sync
    // TODO(perf): why not move this to the action fn?
    if (modelValue !== ctrl.$modelValue &&
       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
    ) {
      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
      parserValid = undefined;

      var formatters = ctrl.$formatters,
          idx = formatters.length;

      var viewValue = modelValue;
      while (idx--) {
        viewValue = formatters[idx](viewValue);
      }
        
      if (ctrl.$viewValue !== viewValue) {
        ctrl.$$updateEmptyClasses(viewValue);
        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
        ctrl.$render();

        ctrl.$$runValidators(modelValue, viewValue, noop);
      }
    }

    return modelValue;
  });

$render要领平常是当ng-model的值发生变化的时刻就会触发:

  • 比方ng-model直接放在input,select标签内,那末ng会自动响应ng-model变化后,便会触发这个要领,来使Dom$scope上挂载的属性值坚持雷同.

  • 指令内部封装了input标签,然则ng-model是在指令外部的外部标签下时。平常须要经由过程event handler去挪用ngModel.$setViewValue要领去时DOM Valuescope上挂载的属性值坚持一致。详细的demo就如上例。

ngModel.$render要领是能够从新自定义的:

    ngModel.$render = function() {
        // scope上的属性值,$modelValue, $viewValue已发生变化
        // 应用这些值再次能够再次做响应的处置惩罚,然后更新DOM value
    }

抽时刻把关于ngModel再补上。睡觉。

参考资料:

angular指令中运用ngModelController
Angular中ngModel的$render的详解

    原文作者:苹果小萝卜
    原文地址: https://segmentfault.com/a/1190000005173789
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞