ngModel。$解析器指令

ngModel。$解析器指令

问题描述:

我要动态地添加指令,以形成元素不工作(输入,选择,文本区域...)

<div ng-app="app" ng-controller="ctrl"> 
    <form form-validator> 
    <input type="text" ng-model="model1"> 
    <input type="text" ng-model="model2"> 
    <input type="text" ng-model="model3"> 
    <textarea ng-model="model4"></textarea> 
    <select> 
     <option ng-model="model5" value="1">Name</option> 
    </select> 
    </form> 
</div> 

指令上述

var app=angular.module('app',[]) 
.controller('ctrl',function($scope){ 

}) 
.directive('formValidator',function($compile){ 
    return{ 
     restrict: 'A', 
     link: function(scope, elem, attrs){ 
      //is it possible to do this with one line of code? 
      elem.find('input').attr('validate-field',''); 
      elem.find('select').attr('validate-field',''); 
      elem.find('textarea').attr('validate-field',''); 
      $compile(elem.contents())(scope); 
     } 
    } 
}) 
.directive('validateField',function(){ 
    return{ 
     restrict: 'A', 
     require:['^ngModel'], 
     link: function(scope, element, attr, ctrls){ 
      var valid = false; 
      var ngModel = ctrls[0]; 
      alert('before validation'); 
      ngModel.$parsers.unshift(function (value){ 
       alert('validating'); 
       valid = validator(value); 
       ngModel.$setValidity('required', valid, ctrls); 
       return valid ? value : undefined; 
      }); 
     } 
    } 
}); 

的代码能够添加validate-field属性,以形成元素:

<input type="text" ng-model="model1" validate-field>

问题是ngModel.$parsers.unshift未被调用,alert('before validation');被调用,但alert('validating');未被调用。

我错过了什么?

+0

你应该使用'要求:[ 'ngModel']'里面你'validateField'指令,使其工作..这样的'ngModelController'将可使用。 –

+0

@Pankaj Parkar仍然不工作时,需要:['^ ngModel'],'是否加入 – Digitlimit

+0

请你能告诉我一个你的意思吗? – Digitlimit

目前发生了什么是你formValidator指令链接函数正在评估所有子代validateField指令得到编译。因为link: function(){ .. }函数被视为与postLink函数相同,在所有子项目链接就绪之后被调用。你的情况也是如此。

所以,我会说,确实要调用链接函数,以确保它会在指令编译前添加validate-fields。为此,您需要使用preLink函数。

.directive('formValidator', function($compile) { 
    return { 
     restrict: 'A', 
     link: { 
     pre: function(scope, elem, attrs) { 
      elem.find('input').attr('validate-field', ''); 
      elem.find('select').attr('validate-field', ''); 
      elem.find('textarea').attr('validate-field', ''); 
      $compile(elem.contents())(scope); 
     } 
     } 
    } 
}) 

Plunkr Here


更多更好的版本将编译父指令只有一次

.directive('formValidator', function($compile) { 
    return { 
     restrict: 'A', 
     compile: function(elem, attrs) { 
     elem.find('input').attr('validate-field', ''); 
     elem.find('select').attr('validate-field', ''); 
     elem.find('textarea').attr('validate-field', ''); 
     //removed to avoid infinite directive compile 
     elem.removeAttr('form-validator'); 
     var linkFn = $compile(elem); 
     return function(scope, element, attr) { 
      linkFn(scope); 
     } 
     } 
    } 
    }) 

Check here

+1

因为我一直在努力从很长一段时间.. –

也许,你想使用$formatters

plunker上的示例。

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<!DOCTYPE html> 
 
<html> 
 

 
    <head> 
 
    <script data-require="[email protected]" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular.js"></script> 
 
    <link rel="stylesheet" href="style.css" /> 
 
    <script src="script.js"></script> 
 
    </head> 
 

 
    <body> 
 
    <h1>Angular Directive</h1> 
 
    <div ng-app="app" ng-controller="ctrl"> 
 
     <form form-validator=""> 
 
     <input type="text" ng-model="model1" /> 
 
     <input type="text" ng-model="model2" /> 
 
     <input type="text" ng-model="model3" /> 
 
     <textarea ng-model="model4"></textarea> 
 
     <select ng-model="model5"> 
 
      <option value="1">Name</option> 
 
     </select> 
 
     <button ng-click="model1='A'"> set model 1 value A</button> 
 
     </form> 
 
    </div> 
 
    <script> 
 
     
 
    var app=angular.module('app',[]) 
 
    .controller('ctrl',function($scope){ 
 

 
    }) 
 
    .directive('formValidator',function($compile){ 
 
    return{ 
 
     restrict: 'A', 
 
     priority:10000, 
 
     link: function(scope, elem, attrs){ 
 
      //is it possible to do this with one line of code? 
 
      elem.find('input').attr('validate-field',''); 
 
      elem.find('select').attr('validate-field',''); 
 
      elem.find('textarea').attr('validate-field',''); 
 
      $compile(elem.contents())(scope); 
 
     } 
 
    } 
 
    }) 
 
    .directive('validateField',function(){ 
 
    return{ 
 
     restrict: 'A', 
 
     require:'ngModel', 
 
     link: function(scope, element, attr, ngModel){ 
 
      var valid = false; 
 
      console.log('before validation',ngModel); 
 
      ngModel.$formatters.unshift(function (value){ 
 
       console.log('validating'); 
 
       //valid = validator(value); 
 
       ngModel.$setValidity('required', valid, ngModel); 
 
       return valid ? value : undefined; 
 
      }); 
 
      ngModel.$parsers.unshift(function (value){ 
 
       console.log('$parsers'); 
 
       valid = true; 
 
       ngModel.$setValidity('required', valid, ngModel); 
 
       return valid ? value : undefined; 
 
      }); 
 
     } 
 
    } 
 
    }); 
 
    </script> 
 
    </body> 
 

 
</html>

+0

感谢您为您+1回应 – Digitlimit