ng-model指令

概述

ng-model指令的作用是把輸入型的元素(input,select,textarea等)和scope中的數(shù)據(jù)進(jìn)行綁定的作用,也可以用在自定義的form元素上。ng-model指令需要和input、select等指令進(jìn)行配合使用。
同時ng-model實現(xiàn)了一些默認(rèn)的數(shù)據(jù)校驗的功能,比如:url、email等格式校驗。ng-model還實現(xiàn)了數(shù)據(jù)狀態(tài)的控制,比如:數(shù)據(jù)是否有效,是否是新數(shù)據(jù)等。如果ng-model在一個form指令中,ng-model指令會把自己的controller添加到form中去,和form建立關(guān)聯(lián),具體可以看form指令的說明。

詳細(xì)說明

ng-model指令的restrict屬性為'A',所以只支持屬性的方式。會依賴form指令(可選),ng-model-option(可選)。

指令的compile

ng-model的compile實現(xiàn)了pre和post兩個函數(shù),在pre函數(shù)中主要進(jìn)行的是把ng-model的controller添加到父form中去。核心代碼為:

formCtrl.$addControl(modelCtrl);

attr.$observe('name', function(newValue) {
  if (modelCtrl.$name !== newValue) {
    modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
  }
});

scope.$on('$destroy', function() {
  modelCtrl.$$parentForm.$removeControl(modelCtrl);
});

這段代碼主要實現(xiàn)的功能:
1、把model的controller添加的form的controller中去,具體實現(xiàn)過程在form指令中。
2、監(jiān)測屬性name,如果屬性值發(fā)生了變化,就修改form指令中的信息。
3、在ng-model指令銷毀的時候刪除form指令中的信息。

在post部分實現(xiàn)了對多個消息的監(jiān)聽,代碼為:

if (modelCtrl.$options.getOption('updateOn')) {
  element.on(modelCtrl.$options.getOption('updateOn'), function(ev) {
     modelCtrl.$$debounceViewValueCommit(ev && ev.type);
  });
}

element.on('blur', function() {
  if (modelCtrl.$touched) return;

  if ($rootScope.$$phase) {
    scope.$evalAsync(modelCtrl.$setTouched);
  } else {
    scope.$apply(modelCtrl.$setTouched);
  }
});

在這里主要進(jìn)行了兩個過程:
1、監(jiān)聽ng-model-option中updateOn指定的消息,調(diào)用model controller的方法,進(jìn)行數(shù)據(jù)更新。
2、監(jiān)聽blur消息,會調(diào)用$apply或者$evalAsync方法進(jìn)行頁面更新。

指令的controller

在controller中定義了很多個方法:

方法 說明
$$initGetterSetters 初始化get和set方法,需要和option配合使用
$render 默認(rèn)是空函數(shù)
$isEmpty 判斷一個值是不是空的
$$updateEmptyClasses 更新是否為empty的css類,設(shè)置ng-empty和ng-not-empty類
$setPristine 標(biāo)記數(shù)據(jù)是新的,刪除ng-dirty類,添加ng-pristine類
$setDirty 標(biāo)記數(shù)據(jù)被修改過,和$setPristine剛好相反,會調(diào)用父form的$setDirty
$setUntouched 標(biāo)記為未觸摸狀態(tài),會設(shè)置ng-untouched類
$setTouched 和$setUntouched剛好相反
$rollbackViewValue 數(shù)據(jù)回滾
$validate 重新計算數(shù)據(jù)的有效性,受option的allowInvalid屬性影響
$$runValidators 直接運行有效性判斷
$commitViewValue 提交數(shù)據(jù)到scope
$$parseAndValidate 解析數(shù)據(jù),然后判斷有效性,如果有效就會添加到scope中去
$$writeModelToScope 把model中的數(shù)據(jù)寫入scope中去
$setViewValue 設(shè)置view里的值
$$debounceViewValueCommit 默認(rèn)數(shù)據(jù)提交函數(shù)

最后controller中還添加了數(shù)據(jù)監(jiān)控:

$scope.$watch(function ngModelWatch() {
   var modelValue = ngModelGet($scope);

   // 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
       // eslint-disable-next-line no-self-compare
      (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();

       // It is possible that model and view value have been updated during render
       ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop);
     }
   }

   return modelValue;
 });

在這段代碼中主要干的事情:
1、獲取ng-model綁定的值
2、根據(jù)$formatters屬性指定的內(nèi)容進(jìn)行數(shù)據(jù)格式化,所有的格式化函數(shù)都會被迭代執(zhí)行。
3、更新數(shù)據(jù),包括更新class,運行有效性校驗等。

樣例代碼

<!DOCTYPE html>
<html lang="en" ng-app="app">
<!--<html>-->
<head>
    <title>Test</title>
</head>
<body>
<style>
    .my-input {
        transition:all linear 0.5s;
        background: transparent;
    }
    .my-input.ng-invalid {
        color:white;
        background: red;
    }
</style>
<p id="inputDescription">
    Update input to see transitions when valid/invalid.
    Integer is a valid value.
</p>
<form name="testForm" ng-controller="ExampleController">
    <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
           aria-describedby="inputDescription" />
</form>
<script src="./node_modules/angular/angular.js" type="text/javascript"></script>
<script>
    angular.module('app', [])
            .controller('ExampleController', ['$scope', function ($scope) {
                $scope.val = '1';
            }]);
</script>
</body>
</html>

這段代碼實現(xiàn)了對輸入數(shù)據(jù)進(jìn)行綁定、格式校驗的功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容