我对Angular相当陌生。 我有一个表单,用户需要为9个不同的端口输入字段分配端口号(上下文:它是服务器环境配置的一种形式)。 验证要求是不能分配两次端口号,因此每个9端口号都必须是唯一的。
为此,我有一个名为“srb-unique-port”的自定义验证指令 ,将其分配给我的输入字段。
指示:
(function () { 'use strict'; angular .module('account') .directive('srbUniquePort', [srbUniquePort]); function srbUniquePort() { return { restrict: 'A', require: 'ngModel', scope: true, link: function (scope, element, attrs, ngModel) { ngModel.$validators.srbUniquePort = function (val) { if (val == null || val == undefined || val == "" || val==0) return true; var fieldName = attrs.name; var configuration = scope.$eval(attrs.srbUniquePort); var portFieldsToCheck = [ "myRestServicePort", "myRestServicePortSSL", "alfrescoPortHttp", "alfrescoPortHttps", "alfrescoPortTomcatShutdown", "alfrescoPortAJP", "alfrescoPortMySql", "alfrescoPortJOD", "alfrescoPortVti" ]; for (var i = 0; i < portFieldsToCheck.length; i++) { if (fieldName!=portFieldsToCheck[i] && configuration[portFieldsToCheck[i]] == val) { return false; } } return true; } } } } })();HTML表单(摘录,仅显示9个字段中的2个):
... <md-input-container> <label for="company" translate>COMPANY.CONFIGURATION.DBLIB_WEB_SRVC_PORT</label> <input ng-model="vm.configuration.dblibWebSrvcPort" name="dblibWebSrvcPort" srb-unique-port="vm.configuration"> <div ng-messages="configurationForm.dblibWebSrvcPort.$error"> <div ng-message when="srbUniquePort"> <span translate>COMPANY.CONFIGURATION.VALIDATION.PORT_NOT_UNIQUE</span> </div> </div> </md-input-container> <md-input-container> <label for="company" translate>COMPANY.CONFIGURATION.DBLIB_WEB_SRVC_PORT_SSL</label> <input ng-model="vm.configuration.dblibWebSrvcPortSLL" name="dblibWebSrvcPortSLL" srb-unique-port="vm.configuration"> <div ng-messages="configurationForm.dblibWebSrvcPortSLL.$error"> <div ng-message when="srbUniquePort"> <span translate>COMPANY.CONFIGURATION.VALIDATION.PORT_NOT_UNIQUE</span> </div> </div> </md-input-container> ...它基本上适用于我当前正在输入值的字段。 但问题是,当我更改一个输入字段的值时,我需要重新验证所有其他依赖字段。 但我不确定最好的方法是什么,以便在这里不会遇到无限循环,因为所有字段都分配了“srb-unique-port”。
我已经看过StackOverflow并发现了这个非常类似的问题:
带有范围的Angular指令。$ watch强制验证其他字段
使用此plunker示例代码: http ://plnkr.co/edit/YnxDDAUCS2K7KyXT1AXP?p = preview
但提供的示例有所不同:它只是关于密码和密码重复字段,其中只有一个字段具有分配的验证指令。 所以它与我的情况有所不同。
我试图在我的上面的代码中添加这个:
scope.$watch(ngModel, function (newValue, oldValue) { ngModel.$validate(); });但是这会导致无限循环(为什么ngModel经常在没有任何进一步操作的情况下进行更改,除了验证应该始终导致相同?)。
I'm fairly new to Angular. I have a form where the user need to assign port numbers to 9 different port input fields (context: it's a form for a server environment configuration). The validation requirement is that no port number can be assigned twice, so each of the 9 port numbers needs to be unique.
For that, I have a custom validation directive called "srb-unique-port", which I assign to my input fields.
Directive:
(function () { 'use strict'; angular .module('account') .directive('srbUniquePort', [srbUniquePort]); function srbUniquePort() { return { restrict: 'A', require: 'ngModel', scope: true, link: function (scope, element, attrs, ngModel) { ngModel.$validators.srbUniquePort = function (val) { if (val == null || val == undefined || val == "" || val==0) return true; var fieldName = attrs.name; var configuration = scope.$eval(attrs.srbUniquePort); var portFieldsToCheck = [ "myRestServicePort", "myRestServicePortSSL", "alfrescoPortHttp", "alfrescoPortHttps", "alfrescoPortTomcatShutdown", "alfrescoPortAJP", "alfrescoPortMySql", "alfrescoPortJOD", "alfrescoPortVti" ]; for (var i = 0; i < portFieldsToCheck.length; i++) { if (fieldName!=portFieldsToCheck[i] && configuration[portFieldsToCheck[i]] == val) { return false; } } return true; } } } } })();HTML form (excerpt, just showing 2 of the 9 fields):
... <md-input-container> <label for="company" translate>COMPANY.CONFIGURATION.DBLIB_WEB_SRVC_PORT</label> <input ng-model="vm.configuration.dblibWebSrvcPort" name="dblibWebSrvcPort" srb-unique-port="vm.configuration"> <div ng-messages="configurationForm.dblibWebSrvcPort.$error"> <div ng-message when="srbUniquePort"> <span translate>COMPANY.CONFIGURATION.VALIDATION.PORT_NOT_UNIQUE</span> </div> </div> </md-input-container> <md-input-container> <label for="company" translate>COMPANY.CONFIGURATION.DBLIB_WEB_SRVC_PORT_SSL</label> <input ng-model="vm.configuration.dblibWebSrvcPortSLL" name="dblibWebSrvcPortSLL" srb-unique-port="vm.configuration"> <div ng-messages="configurationForm.dblibWebSrvcPortSLL.$error"> <div ng-message when="srbUniquePort"> <span translate>COMPANY.CONFIGURATION.VALIDATION.PORT_NOT_UNIQUE</span> </div> </div> </md-input-container> ...It basically works for the field that I am current entering a value into. But the problem is that when I change the value of one input field, I need to re-validate all other depending fields as well. But I am not sure what the best way is in order to not run into an endless loop here, since all fields have the "srb-unique-port" assigned.
I already looked on StackOverflow and found this very similar question:
Angular directive with scope.$watch to force validation of other fields
with this plunker sample code: http://plnkr.co/edit/YnxDDAUCS2K7KyXT1AXP?p=preview
but the example provided there is different: it's only about a password and a password repeat field, where only one field has the validation directive assigned. So it differs from my case.
I tried to add this in my above code:
scope.$watch(ngModel, function (newValue, oldValue) { ngModel.$validate(); });but this causes endless loops (why does the ngModel frequently change here without any further action other than a validation which should always result to the same?).
最满意答案
这是我最终解决的问题。 看起来有点黑了我,但它的作品。
(function () { 'use strict'; angular .module('account') .directive('srbUniquePort', [srbUniquePort]); function srbUniquePort() { return { restrict: 'A', require: 'ngModel', scope: true, link: function (scope, element, attrs, ngModel) { function hasAValue(field) { return !!field; } ngModel.$validators.srbUniquePort = function (val) { var fieldName = attrs.name; var configuration = scope.$eval(attrs.srbUniquePort); var portFieldsToCheck = [ "dblibWebSrvcPort", "dblibWebSrvcPortSLL", "myRestServicePort", "myRestServicePortSSL", "alfrescoPortHttp", "alfrescoPortHttps", "alfrescoPortTomcatShutdown", "alfrescoPortAJP", "alfrescoPortMySql", "alfrescoPortJOD", "alfrescoPortVti" ]; configuration[fieldName] = val; if (scope.$parent.configuration == undefined) { scope.$parent.configuration = JSON.parse(JSON.stringify(configuration)); } scope.$parent.configuration[fieldName] = val; // compare each port field with each other and in case if equality, // remember it by putting a "false" into the validityMap helper variable var validityMap = []; for (var i = 0; i < portFieldsToCheck.length; i++) { for (var j = 0; j < portFieldsToCheck.length; j++) { if (portFieldsToCheck[i] != portFieldsToCheck[j]) { var iFieldHasAValue = hasAValue(scope.$parent.configuration[portFieldsToCheck[i]]); var jFieldHasAValue = hasAValue(scope.$parent.configuration[portFieldsToCheck[j]]); var valHasAValue = hasAValue(val); if (iFieldHasAValue && jFieldHasAValue && scope.$parent.configuration[portFieldsToCheck[i]] == scope.$parent.configuration[portFieldsToCheck[j]] ) { validityMap[portFieldsToCheck[i]] = false; validityMap[portFieldsToCheck[j]] = false; } } } } // in the end, loop through all port fields and set // the validity here manually for (var i = 0; i < portFieldsToCheck.length; i++) { var valid = validityMap[portFieldsToCheck[i]]; if (valid == undefined) valid = true; ngModel.$$parentForm[portFieldsToCheck[i]].$setValidity("srbUniquePort", valid); } // ending with the standard validation for the current field for (var i = 0; i < portFieldsToCheck.length; i++) { if (fieldName != portFieldsToCheck[i] && configuration[portFieldsToCheck[i]] == val) { return false; } } return true; } } } } })();This is the solution I ended up with. Looks a bit hacked to me, but it works.
(function () { 'use strict'; angular .module('account') .directive('srbUniquePort', [srbUniquePort]); function srbUniquePort() { return { restrict: 'A', require: 'ngModel', scope: true, link: function (scope, element, attrs, ngModel) { function hasAValue(field) { return !!field; } ngModel.$validators.srbUniquePort = function (val) { var fieldName = attrs.name; var configuration = scope.$eval(attrs.srbUniquePort); var portFieldsToCheck = [ "dblibWebSrvcPort", "dblibWebSrvcPortSLL", "myRestServicePort", "myRestServicePortSSL", "alfrescoPortHttp", "alfrescoPortHttps", "alfrescoPortTomcatShutdown", "alfrescoPortAJP", "alfrescoPortMySql", "alfrescoPortJOD", "alfrescoPortVti" ]; configuration[fieldName] = val; if (scope.$parent.configuration == undefined) { scope.$parent.configuration = JSON.parse(JSON.stringify(configuration)); } scope.$parent.configuration[fieldName] = val; // compare each port field with each other and in case if equality, // remember it by putting a "false" into the validityMap helper variable var validityMap = []; for (var i = 0; i < portFieldsToCheck.length; i++) { for (var j = 0; j < portFieldsToCheck.length; j++) { if (portFieldsToCheck[i] != portFieldsToCheck[j]) { var iFieldHasAValue = hasAValue(scope.$parent.configuration[portFieldsToCheck[i]]); var jFieldHasAValue = hasAValue(scope.$parent.configuration[portFieldsToCheck[j]]); var valHasAValue = hasAValue(val); if (iFieldHasAValue && jFieldHasAValue && scope.$parent.configuration[portFieldsToCheck[i]] == scope.$parent.configuration[portFieldsToCheck[j]] ) { validityMap[portFieldsToCheck[i]] = false; validityMap[portFieldsToCheck[j]] = false; } } } } // in the end, loop through all port fields and set // the validity here manually for (var i = 0; i < portFieldsToCheck.length; i++) { var valid = validityMap[portFieldsToCheck[i]]; if (valid == undefined) valid = true; ngModel.$$parentForm[portFieldsToCheck[i]].$setValidity("srbUniquePort", valid); } // ending with the standard validation for the current field for (var i = 0; i < portFieldsToCheck.length; i++) { if (fieldName != portFieldsToCheck[i] && configuration[portFieldsToCheck[i]] == val) { return false; } } return true; } } } } })();更多推荐
发布评论