Angularjs Form Input Group Validation
With Angular I am using a custom directive to validate one input field. (e.g. email, username, etc.)
In this project, I have a scenario like this:
I need to set the Advance Payment field, this transition must be between min / max value. To install Advance, I have three input texts:
- Spot
- Old car value
- Financed advance
the sum of these three inputs is my Advance value.
So I need to check Advance, but I don't have any input with ng model installed.
What is the best way to check and confirm the value of the down payment?
Do I need to add a directive to all three of these input fields? or better directive for the form?
Any suggestion would 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;
}
});
})();
source to share
Just to give you (and possibly others) another option.
To simplify, you can use input number and its ng-model model is plan.advance . This will allow you to use min / max attributes. You can set hidden input if you don't want to show it.
<input type="number" name="advance" ng-model="plan.advance" min="{{plan.min_advance}}" max="{{plan.max_advance}}" hidden />
Then you can use the inline check for min and max, for example:
<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:
- Your directive is tightly scoped to your controller, so you cannot reuse it elsewhere in your application, and you will need to update it separately if you change one of your scope variables in the future.
- You are essentially duplicating code for functionality that already exists within the framework. This increases the initial cost of development and maintenance efforts along the line.
source to share
I solve my question with a new directive. I don't know if this is being done correctly, but it works fine and the behavior 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();
});
}
};
});
source to share