2015-11-09 84 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>