自定义验证器指令多次与其他指令触发相结合

时间:2015-03-01 11:23:51

标签: angularjs validation angularjs-directive

我有一个自定义验证指令iban,用于检查该值是否为有效(荷兰语)IBAN。该验证器需要将值大写。我还有一个uppercase指令,它将值更改为大写。我想在一个输入元素上组合两个:

<input type="text" ng-model="iban" name="iban" capitalize="" iban="" />

我创建了jsfiddle来证明这种情况。

我正在努力处理正确的执行顺序。如果用户键入一个值,我想首先触发大写,因此iban验证器会收到一个大写的值。如果模型值是从代码设置的,我也想先将其大写。

当用户键入小写字符时,大写指令调用ctrl。$ setViewValue来设置视图值。这会触发解析器的另一次运行。因此,大写指令和iban指令都执行了两次。控制台日志显示:

parsers.capitalize: nL12HHBA0429672071
  uppercasing: nL12HHBA0429672071 => NL12HHBA0429672071, setting view value
parsers.capitalize: NL12HHBA0429672071
  uppercasing: NL12HHBA0429672071 already uppercased
parsers.iban: NL12HHBA0429672071
  setting validity to: true
  returning NL12HHBA0429672071
parsers.iban: NL12HHBA0429672071
  setting validity to: true
  returning NL12HHBA0429672071

我认为不打算多次遍历解析器。

另一个问题是当我将代码中的值设置为已经大写的无效IBAN时(我小提琴中的最后一个链接)。在这种情况下,大写指令不必执行任何操作。 iban指令格式化程序将有效性设置为false,并返回该值。如果它是小写无效的IBAN,则大写指令将调用setViewValue,从而导致IBAN指令解析器代码执行,这将返回undefined。这样情况会将模型的值更改为undefined。

我是不是太复杂了?我是否应该尝试创建一个iban指令,以确保当用户输入有效的小写iban值时,大写的值会存储在模型中?如果从代码设置,我应该只保留模型中的小写值吗?也许只需在元素上使用style="text-transform: uppercase"来始终显示值,就像它是大写的一样?缺点是如果将模型设置为有效但较低的值,则表单将显示大写的值,该值有效,而模型值实际上无效。

1 个答案:

答案 0 :(得分:1)

这里肯定有些复杂。在玩弄时,也有一些角度怪异(至少在我眼里 - 我会达到这个目的)。

此处介绍的一个复杂因素是您的capitalize $formatter实际上更改了模型值。我认为这违背了格式化程序函数的意图(转换model -> view方向的值)。视图(以及格式化程序通过其指令位于视图中)应仅在更改源自视图时更改模型。这使得模型成为事实的来源,如果它被设置为无效值,那么就是这样 - 有效性应该反映在视图中,但它不应该试图“修复”模型。

考虑到这一点,我们还使用$validators进行验证(而不是$ parsers / $ formatters管道):

.directive("iban", function(){
  return {
    require: "?ngModel",
    link: function(scope, element, attrs, ngModel){
      if (!ngModel) return;

      ngModel.$validators.iban = function(modelValue, viewValue){

        // after parser ran, validate the resulting modelValue
        return validate(modelValue);
      };

      function validate(val){
         return modelValue === "VALID IBAN"; // for the sake of example
      }
    }
  };
});

$parsers(更改模型值)和$formatters(更改视图值)在$validators运行之前调用。

另一个复杂性(以及看似Angular的奇怪之处)是,capitalize格式化程序可以使$viewValue对无效$modelValue有效。这本身就行为正确 - 它格式化$viewValue并将有效性保持为假(因为模型是假的)。但是,如果您现在将模型更改为当前设置(且有效)$viewValue,则Angular决定跳过(src)验证器(因为它发现新旧{{1}之间没有区别尽管模型和视图值都是有效的,但有效性永远不会变得有效。同样,对于有效无效的情况(无效的低案例值永远不会使模型无效)。

然而,这是一种罕见的情况,如果应该完全避免编码。为什么?因为模型很少(如果有的话)假设无效值并且应该在有效范围内运行。

$viewValues通过将模型设置为ng-model来获取无效值,从而确保这一点(默认情况下,除非您allowInvalid)。

因此,对于您的问题,请确定在您定义的ViewModel中,小写IBAN是否被视为无效:

  • 如果小写无效,则永远不要将低案例值分配给您的ViewModel undefined属性 - plunker
  • 如果小写有效,则执行不区分大小写的iban验证程序 - plunker