Reputation: 2394
With Angular I use specific directive for validate single input field. (i.e. email, username etc.)
In this project I have this scenario:
I need to set an Advance Payment field, this Advance must be between min/max value. To set the Advance I have three input text:
the sum of those three input is my Advance value.
So I need to validate Advance but I have no a single input with ng-model setted on.
What is the best way to check and validate the Advance Payment value?
I need to add a directive to all those three input fields? or is better a directive for the form?
Any suggestion will be appreciated.
(function () {
var app = angular.module("myApp", ['ngMessages']);
app.controller('myFormCtrl', function($scope) {
$scope.plan = {};
$scope.plan.advance = 0;
$scope.plan.min_advance = 3000;
$scope.plan.max_advance = 6000;
$scope.updateAdvance = function(){
var advance = 0;
if ($scope.quotationAdvanceType && !isNaN($scope.plan.quotation))
advance += $scope.plan.quotation;
if ($scope.cashAdvanceType && !isNaN($scope.plan.cash))
advance += $scope.plan.cash;
if ($scope.financedAdvanceType && !isNaN($scope.plan.financed))
advance += $scope.plan.financed;
$scope.plan.advance = advance;
}
});
})();
Upvotes: 4
Views: 2411
Reputation: 17372
Just to give you (and perhaps others) another option.
To simplify, you can use a number input with its ng-model set to plan.advance. This will allow you to use the min/max attributes. You can set the input to hidden if you prefer not to display it.
<input type="number" name="advance" ng-model="plan.advance" min="{{plan.min_advance}}" max="{{plan.max_advance}}" hidden />
Then you can use the built in validation for min and max such as:
<span ng-messages="myForm.advance.$error" role="alert">
<span ng-message="min">Minimum not reached.</span>
<span ng-message="max">Maximum exceeded.</span>
</span>
Run the code snippet below to see it in action:
(function () {
var app = angular.module("myApp", ['ngMessages']);
app.controller('myFormCtrl', function ($scope) {
var advance = [];
$scope.plan = {};
$scope.plan.advance = 0;
$scope.plan.min_advance = 3000;
$scope.plan.max_advance = 6000;
$scope.reset = function(val) {
$scope.plan[val] = undefined;
$scope.updateAdvance();
};
$scope.updateAdvance = function () {
advance = [$scope.plan.quotation, $scope.plan.cash, $scope.plan.financed];
$scope.plan.advance = advance.reduce(function (a, b) {
a = a ? a : 0;
b = b ? b : 0;
return a + b;
}, 0);
}
});
})();
@import url("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css");
<script src="https://code.angularjs.org/1.3.15/angular.min.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular-messages.min.js"></script>
<div ng-app="myApp" class="container">
<form name="myForm" ng-controller="myFormCtrl" class="form-horizontal">
<div class="form-group" ng-class="{ 'has-error' : myForm.plan.min_advance.$invalid && myForm.plan.min_advance.$touched}">
<label for="plan.min_advance" class="control-label col-xs-4 col-sm-2">Min Advance</label>
<div class="col-xs-8 col-sm-10">
<input type="number" ng-model="plan.min_advance" class="form-control" />
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : myForm.plan.max_advance.$invalid && myForm.plan.max_advance.$touched}">
<label for="plan.max_advance" class="control-label col-xs-4 col-sm-2">Min Advance</label>
<div class="col-xs-8 col-sm-10">
<input type="number" ng-model="plan.max_advance" class="form-control" />
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : myForm.surname.$invalid && myForm.surname.$touched}">
<div class="col-xs-12">
<label for="surname" class="control-label">Surname</label>
<input type="text" value="" name="surname" id="surname" ng-model="surname" ng-minlength="3" ng-mAXlength="20" required="required" class="form-control" />
<span ng-messages="myForm.surname.$error" class="help-block" role="alert" ng-show="myForm.surname.$touched">
<span ng-message="required">You forgot to enter your surname</span>
<span ng-message="minlength">Surname is too short</span>
<span ng-message="maxlength">Surname is too long</span>
</span>
</div>
</div>
<p>Set the Advance between minimun <strong>{{plan.min_advance | currency}}</strong> and maximum <strong>{{plan.max_advance | currency}}</strong>
</p>
<div class="form-group">
<label for="quotation" class="col-xs-4 col-sm-2 control-label">
<input type="checkbox" name="quotationAdvanceType" ng-model="quotationAdvanceType" ng-change="reset('quotation')"/> Quotation:
</label>
<div class="col-xs-8 col-sm-10">
<input type="number" name="quotation" ng-value="plan.quotation" ng-model="plan.quotation" ng-change="updateAdvance()" class="form-control" ng-disabled="!quotationAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
</div>
</div>
<div class="form-group">
<label for="cash" class="col-xs-4 col-sm-2 control-label">
<input type="checkbox" name="cashAdvanceType" ng-model="cashAdvanceType" ng-change="reset('cash')" /> Cash:
</label>
<div class="col-xs-8 col-sm-10">
<input type="number" name="cash" ng-value="plan.cash" ng-model="plan.cash" ng-change="updateAdvance()" class="form-control" ng-disabled="!cashAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
</div>
</div>
<div class="form-group">
<label for="financed" class="col-xs-4 col-sm-2 control-label">
<input type="checkbox" name="financedAdvanceType" ng-model="financedAdvanceType" ng-change="reset('financed')" /> Financed:
</label>
<div class="col-xs-8 col-sm-10">
<input type="number" name="financed" ng-value="0" ng-model="plan.financed" ng-change="updateAdvance()" class="form-control" ng-disabled="!financedAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
</div>
</div>
<div ng-class="{'has-error' : myForm.advance.$invalid && (quotationAdvanceType || cashAdvanceType || financedAdvanceType) && (myForm.quotation.$dirty || myForm.cash.$dirty || myForm.financed.$dirty)}">
<input type="number" name="advance" ng-model="plan.advance" min="{{plan.min_advance}}" max="{{plan.max_advance}}" hidden />
<p class="help-block">Total Advance: <strong>{{plan.advance ? (plan.advance | currency) : 'none'}}</strong>
<span ng-messages="myForm.advance.$error" role="alert" ng-show="myForm.quotation.$dirty || myForm.cash.$dirty || myForm.financed.$dirty">
<span ng-message="min">Minimum not reached.</span>
<span ng-message="max">Maximum exceeded.</span>
</span>
</p>
</div>
<button type="submit" class="btn btn-primary" ng-disabled="myForm.$invalid">Send</button>
</form>
</div>
Is there an advantage over your custom directive approach? I would say yes and here's why:
Upvotes: 2
Reputation: 2394
I solve my question with a brand new directive. I don't know if this is the right way to do that, but it works fine and the behaviour is correct.
app.directive('totalAdvance', function() {
return {
restrict: 'E',
require: '^form',
link: function(scope, element, attrs, formCtrl) {
var advanceValue = 0;
var advanceValidator = function() {
if (advanceValue >= attrs.min && advanceValue <= attrs.max){
formCtrl.$setValidity('minAdvance', true);
formCtrl.$setValidity('maxAdvance', true);
return advanceValue;
}else if (advanceValue < attrs.min) {
formCtrl.$setValidity('minAdvance', false);
formCtrl.$setValidity('maxAdvance', true);
return null;
}else if (advanceValue > attrs.max){
formCtrl.$setValidity('minAdvance', true);
formCtrl.$setValidity('maxAdvance', false);
return null;
}
};
scope.$watch('plan.advance', function(value) {
advanceValue = value;
return advanceValidator();
});
scope.$watch('plan.min_advance', function() {
return advanceValidator();
});
scope.$watch('plan.max_advance', function() {
return advanceValidator();
});
}
};
});
Upvotes: 1