2016-08-05 33 views
0

我想为Angular的ngMessages添加一个自定义验证函数。Angular ngMessages - 访问多个表单值

具体而言,我想的几个输入(输入的数量将是动态的,但现在坚持使用2)的值与总100

我已经创建了一个新的指令称为totalOneHundred其触发一个表单的变化,但我不知道如何访问link:回调中的其他表单值。

我已在下面发布我的代码。有什么我失踪?另外,如果有更好的方法来完成这个功能(例如控制器中的sum()功能和ng-show),请给我打电话。

感谢您的帮助。

形式:

<!-- input box to be validated --> 
<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound" total-one-hundred required> 

<!-- validation messages --> 
<div ng-messages="form['lowBound'].$error" role="alert"> 
    <div ng-message="required">Cannot be empty</div> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

<!-- input box to be validated --> 
<input type="number" class="form-control" name="highBound" ng-model="ctrl.highBound" total-one-hundred required> 

<!-- validation messages --> 
<div ng-messages="form['highBound'].$error" role="alert"> 
    <div ng-message="required">Cannot be empty</div> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

的指令:

return { 
    restrict: "A", 

    require: ["^^form", "ngModel"], 

    link: function(scope, element, attributes, controllers) { 

     // At first, form is assigned the actual form controller... 
     const form = controllers[0]; 
     const model = controllers[1]; 

     model.$validators.totalOneHundred = function (modelValue, form, element, scope) { 

      // however, the value of form here is "1". 
      // modelValue is the value of the triggering input, 
      // but how can I access the other form inputs? 
      return true; 

     }; 

    } 
}; 

回答

1

最初我把你的代码和实施this fiddle。 A父母控制器的sum()方法计算总数(在小提琴中很简单,但由于父控制器知道整个动态模型,所以在实际情况下也是可行的)。该total-one-hundred需要的总和作为参数,即:

<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound" 
    total-one-hundred="ctrl.sum()" required /> 

唉,它不能正常工作!问题:每个输入都显示“任务总和= 100”错误。如果您更改字段并且总数正确,则该字段变为有效并停止显示该消息。但其他领域不!


编辑:嗯,这可以工作,甚至这种方式。秘诀在于在每个验证指令的总和上添加一个监视,并在该字段上重新应用验证;新的链接功能:

link: function(scope, element, attributes, controllers) { 
     const model = controllers[0]; 
     var totalEvaluator = $parse(attributes['totalOneHundred']); 

     scope.$watch(totalEvaluator, function(newval, oldval) { 
     if(newval !== oldval) { 
      model.$validate(); 
     } 
     }) 

     model.$validators.totalOneHundred = function (modelValue) { 
     return totalEvaluator(scope) === 100; 
     }; 
    } 

(!请注意,这个收费是每场额外的手表)

现在然而,sum()功能(可能潜在地是昂贵的)被称为多次。看着这个函数的输入,只有当它们改变时才调用它,可能会改善情况。

更新的小提琴:(我还是喜欢模型验证 - 见最后中─不过这是好事,知道所有的选择和他们的副作用)https://jsfiddle.net/m8ae0jea/1/


这是一个概念性的问题跨场验证。验证属于哪里?如果你可以重构你的模型,那么被验证的是整个对象,那么你可以使用Angular的自定义控件,如this fiddle

现在的模式是这样的:

this.model = { 
    lowBound: <a number>, 
    highBound: <a number> 
}; 

而且有一个编辑器整个模型,完成与自己的消息:

<model-editor name="entireModel" ng-model="ctrl.model" form="form" 
    total-one-hundred="ctrl.sum()"></model-editor> 
<div ng-messages="form['entireModel'].$error" role="alert"> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

正如你所看到的总验证适用于整个模型。

第二个示例正常工作,如果您只能用一条消息进行整个“全部”验证。但我不喜欢它...

Angular的验证是(恕我直言)一个快速和肮脏的解决方案适合简单的事情。假设一个字段不能为空,另一个字段必须遵守正则表达式等等。对于复杂的事情(例如这种情况),我觉得在视图中定义业务逻辑是不合适的。我更喜欢进行模型验证并将验证结果与Angular绑定。就此而言,我创建了非常适合这种事情的egkyron

+0

非常感谢您的详细回复。我可能正在尝试在这里推动角度验证。我会看看你链接的资源,看看什么最适合我的用例。再次感谢! – Mac