2015-11-09 57 views
0

有三个输入字段AngularJS:自定义验证基于链接输入字段

<input type="text" name="foo1" ng-model="data.input1"/> 
<ng-messages for="forms.myForm.foo1" role="alert"> 
    <ng-message when="oneRequired"> Please set foo1 (or foo2 or foo3) </ng-message> 
<ng-messages> 

<input type="text" name="foo2" ng-model="data.input2"/> 
<ng-messages for="forms.myForm.foo2" role="alert"> 
    <ng-message when="oneRequired"> Please set foo2 (or foo1 or foo3) </ng-message> 
<ng-messages> 

<input type="text" name="foo3" ng-model="data.input3"/> 
<ng-messages for="forms.myForm.foo3" role="alert"> 
    <ng-message when="oneRequired"> Please set foo3 (or foo1 or foo2) </ng-message> 
<ng-messages> 

我要保证至少一个输入字段值设置。在这种情况下,不仅当前验证字段$ error应该评估为'false',而且也应该评估为所有其他字段。所有消息应该消失。

我的第一个想法是用一个指令和一个唯一的ID字段链接在一起:

<input type="text" name="foo1" ng-model="data.input1" one-required="i1_i2_i3_link_identifier/> 

也许我可以用一个(单)服务控制器的登记和当前值。但我没有想法确保所有链接的控制器(在指令中使用)在验证错误时更新。

+0

我也使用指令用来显示形式的一些fieds信息。 我将表单名称传递给指令,以便指令可以获得输入/错误/有效...也许$ scope。$ watch in controller或$ scope。$ apply()in directive可以帮助 – AlainIb

+0

您是否可以检查输入在控制器中? –

+0

@OlaviSau:我可以但我不知道如何让其他控制器使用这项服务。 –

回答

1

我强烈建议您使用https://github.com/turinggroup/angular-validator指令。它非常灵活,并且很容易设置您的自定义验证器。我能够摆脱ng消息,并用这个指令清理我的html代码。

您可以在您的控制器或服务中设置自定义验证器,以便在整个站点中使用。

  <input type = "text" 
        name = "firstName" 
        class = "form-control" 
        ng-model = "form.firstName" 
        validator = "myCustomValidator(form.firstName)" 
        validate-on="dirty" 
        required></div> 

这里是一个plunker和代码你:http://plnkr.co/edit/X5XdYYekT4YZH6xVBftz?p=preview正如你可以看到这是很笨重,有大量的代码。使用角度验证器,您可以将代码减少为在输入内联,并添加控制器功能。

<form name="myForm"> 
     <input type="text" name="foo1" ng-model="data.input1" required/> 
     <div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error"> 
     <ng-messages for="myForm.foo1" role="alert"> 
      <ng-message="required"> Please set foo1 (or foo2 or foo3) </ng-message> 
     </ng-messages> 
     </div> 
     <br/> 
     <input type="text" name="foo2" ng-model="data.input2" required/> 
     <div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error"> 
     <ng-messages for="myForm.foo2" role="alert"> 
      <ng-message="required"> Please set foo2 (or foo2 or foo3) </ng-message> 
     </ng-messages> 
     </div> 
     <br/> 
     <input type="text" name="foo3" ng-model="data.input3" required/> 
     <div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error"> 
     <ng-messages for="myForm.foo3" role="alert"> 
      <ng-message="required"> Please set foo3 (or foo2 or foo3) </ng-message> 
     </ng-messages> 
     </div> 
     <br/> 
    </form> 
+0

这可能是一个选项。但我真的想用基本的角度手段来解决这个问题 –

0

我解决了问题,使用一个中央服务,保存值和回调注册表。回调被称为所有的时间中,当输入的变化(使用观察者):

angular.module('myApp', []); 
 

 
    angular.module('myApp').controller('myFormController', function($scope) { 
 
      $scope.data = { 
 
      i1: "remove", 
 
      i2: "all", 
 
      i3: "values" 
 
      }; 
 
    }); 
 

 
    angular.module('myApp').factory('oneRequiredService', function() { 
 
      var service = {}; 
 
      var container = {}; 
 
      var observerCallbacks = {}; 
 

 
      var isValid = function(groupId) { 
 
      var valid = false; 
 

 
      var modelStates = container[groupId]; 
 
      angular.forEach(modelStates, function(modelValid) { 
 
       valid = valid || (modelValid ? true : false); 
 
      }); 
 
      return valid; 
 
      }; 
 

 
      var isRegistered = function(groupId) { 
 
      return container.hasOwnProperty(groupId); 
 
      }; 
 

 
      var notifyAll = function(key) { 
 
      var valid = isValid(key); 
 
      if (isRegistered(key)) { 
 
       angular.forEach(observerCallbacks[key], function(callback, index) { 
 
       callback(valid); 
 
       }); 
 
      }; 
 
      }; 
 

 
      service.register = function(groupId, scopeId, callback) { 
 
      this.updateValue(groupId, scopeId, undefined); 
 
      if (callback) { 
 
       this.registerCallback(groupId, callback); 
 
      } 
 
      }; 
 

 
      service.registerCallback = function(groupId, callback) { 
 
      if (callback) { 
 
       observerCallbacks[groupId] = observerCallbacks[groupId] || []; 
 
       observerCallbacks[groupId].push(callback); 
 
      }; 
 
      }; 
 

 
      service.updateValue = function(groupId, scopeId, value) { 
 
      container[groupId] = container[groupId] || {}; 
 
      container[groupId][scopeId] = value; 
 
      notifyAll(groupId); 
 
      }; 
 

 
      return service; 
 
     }); 
 

 
     angular.module('myApp').directive('oneRequired', function(oneRequiredService) { 
 
      return { 
 
      restrict: "A", 
 
      require: 'ngModel', 
 
      scope: true, 
 
      link: function(scope, element, attrs, ctrl) { 
 

 
       var modelAttr = attrs["ngModel"]; 
 
       
 
       var linkIdentifier = attrs["oneRequired"]; 
 
       
 
       var updateCurrentState = function(isValid) { 
 
       scope._valid = isValid; 
 
       }; 
 

 
       scope.$watch(modelAttr, function(newVal, oldVal) { 
 
       oneRequiredService.updateValue(linkIdentifier, scope.$id, newVal); 
 
       }); 
 

 
       scope.$watch('_valid', function(newVal, oldVal) { 
 
       ctrl.$setValidity('oneRequired', newVal); 
 
       }); 
 

 
       oneRequiredService.register(linkIdentifier, scope.$id, updateCurrentState); 
 
      } 
 
      } 
 
     });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script> 
 

 
<body ng-app="myApp"> 
 
     <form ng-controller="myFormController" name="forms.myForm"> 
 

 
     <label for="i_1">i_1</label> 
 
     <input id="i_1" name="i1" type="text" one-required="foo-bar" ng-model="data.i1" /> 
 
     <span> i1-err-one-required: {{forms.myForm.i1.$error.oneRequired}} </span> <br> 
 
      
 
     <label for="i_2">i_2</label> 
 
     <input id="i_2" name="i2" type="text" one-required="foo-bar" ng-model="data.i2"/> 
 
     <span> i2 err-one-required: {{forms.myForm.i2.$error.oneRequired}} </span> <br> 
 
      
 
     <label for="i_3">i_3</label> 
 
     <input id="i_3" name="i3" type="text" one-required="foo-bar" ng-model="data.i3"/> 
 
     <span> i3-err-one-required: {{forms.myForm.i3.$error.oneRequired}} </span> <br> 
 
     </form> 
 
    </body>