compare two input field values in a table using angular - angularjs

I am a beginner in angularjs and I am trying to make a dynamic table but with custom validations. for instance, I have 2 input fields namely totalSalary and pension paid. The pension paid entered should not be greater than the totalSalary. I am trying to build a custom directive for the pension paid field but how to get the value of the totalSalary field to do the comparison?
Thanks to help.
Ashley
Updated:
This is the table I have made so far as per the next link. Dynamic table made so far
Below are two fields I need to compare.
<td><input type="text" class="form-control" ng-model="employee.details.salary" fcsa-number required/></td>
<td><input type="text" class="form-control" ng-model="employee.details.pension" fcsa-number not-greater-than-yearly-sal required/></td>
The directive so far I have worked on is as per below. I got the value of pension1 but now how to get the value of salary. On leaving the input for pension1, if the amount is greater than the salary, it should prompt the user and clear the value.
angular.module('app').directive("notGreaterThanYearlySal", function () {
return {
restrict: "A",
require: "?ngModel",
link: function (scope, element, attributes, ngModel) {
element.bind('blur', function(event){
alert(element.val());
});
}
};
});

One way you achieve with custom directives
for example here i match email :
<p>Email:<input type="email" name="email1" ng-model="emailReg">
Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-match="emailReg"></p>
<span data-ng-show="myForm.emailReg2.$error.match">Emails have to match!</span>

Without using custom Directives :
<button ng-click="add()></button>
<span ng-show="IsMatch">Emails have to match!</span>
$scope.add = function() {
if ($scope.emailReg != $scope.emailReg2) {
$scope.IsMatch=true;
return false;
}
$scope.IsMatch=false;
}

I think this is a really neat way of doing this. You could set something like ng-max to the second input and set it's value as the other inputs ng-model. Then according to this you could show a error message.
<form name="numberForm">
First input:
<input type="number" name="number1" ng-model="number1">
Second input:
<input type="number" name="number2" ng-model="number2" ng-max="number1">
<span ng-show="numberForm.number2.$error.max">This field should not be larger than the other</span>
</form>
Here's a JSFiddle: https://jsfiddle.net/thepio/dpgfuy06/

No need for directive!
Make the following changes in your code:-
Use ng-repeat to iterate over your array of elements in the employee details like this:-
<div ng-repeat ="details in employee.details">
</div>
where all your elements should be put in the employee.details array
Accordingly change your ng-model to "details.pension" and "details.salary"
Make a div below your input fields and specify the condition you want in ng-show
and display an error message for the same.
For instance, in your case it would look like:-
<div ng-show="details.pension > details.salary">Pension cannot be greater than salary!
</div>
This should do the validations there and then itself.

Using custom directive:
.directive("compareTo", function () {
return {
require: "ngModel",
scope: {
otherModelValue: "=compareTo"
},
link: function (scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function (modelValue) {
return modelValue == scope.otherModelValue;
};
scope.$watch("otherModelValue", function () {
ngModel.$validate();
});
}
};
})

Related

AngularJS trigger field validation after form loads

I have set of data fields.
They look like this:
// Read-Only
<div class="field-group" ng-if="feature.edit == false">
<div class="label" ng-class="{'feature-required': field.Validations.Required === true}">{{field.Label}}</div>
<div class="value">{{field.Value}}</div>
</div>
// Editor
<div class="field-group" ng-show="feature.edit == true">
<label for="F{{field.FieldID}}">
<span ng-class="{'feature-required': field.Validations.Required === true, 'feature-notrequired': field.Validations.Required === false}">{{field.Label}}</span>
<input type="text"
id="F{{field.FieldID}}"
name="F{{field.FieldID}}"
ng-change="onFieldUpdate()"
ng-model="field.Value"
jd-field-attributes attr-field="field"
jd-validate on-error="onFieldError"
field="field">
</label>
</div>
feature.edit is controlled by button and you can have data read-olny or editable. Each field has some validation, usually, if required it must be different than null.
I want to trigger that validation after I click edit and input fields show up.
One way to do it is to loop through all input fields and use jQuery trigger("change"). I have to do it with some delay (it takes Angular to populate all fields).
Is there any way to trigger ng-change or run onFieldUpdate(), after that input becomes visible?
I have tried ng-init, but it didn't work.
You could move your validation logic to custom validators in the ngModel $validators pipeline. Functions you add to this pipeline will evaluate against the input model value every time it changes and automatically add the associated valid/invalid classes to the input.
Here's an example of how you can add custom validators:
app.directive('moreValidation', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.first = function(input) {
return true; // add your custom logic here
}
ngModel.$validators.second = function(input) {
return true;
}
ngModel.$validators.third = function(input) {
return true;
}
}
};
});
// markup
<input type="text" ng-model="modelObject" more-validation />
Here's a small working plnkr example: http://plnkr.co/edit/mKKuhNqcnGXQ4sMePrym?p=preview

How to limit the user not to enter number greater than four?

I have a input text box,where only numbers are allowed to enter.numbers="numbers-only" is the directive that prevents users to enter anything rather than numbers.Now I should not allow the user to enter the number with value more than 4.Plz help
HTML:
<input type='text' name='pat' id='pat' ng-model='dpmArr.pt_no' class='form-control' numbers-only="numbers-only">
There are 2 attributes that allow you to add a minimum and maximum to your input they are minand max
so just add max ="4" into your tags
Your Own directive
You can add another directive like this:
in html:
<input with-max-limit max-limit="9" type="text" ng-required="true" name="search" ng-model="value">
And in your js:
.directive("withMaxLimit", function () {
return {
require: ["ngModel"],
restrict: "A",
link: function ($scope, $element, $attrs) {
var modelName = $attrs.ngModel;
var maxLimit = parseInt($attrs.maxLimit, 10);
$scope.$watch(modelName, function (newValue, oldValue) {
if (newValue && (newValue.length > maxLimit || newValue.indexOf(' ') >= 0)) {
$scope[modelName] = oldValue;
}
});
}
}
})
Take into account that it is draft version and you could easily modify it.
Also pay attention to Angular's naming convention that directive has name withMaxLimit but in html it will be with-max-limit.
AngularJS Filter
Also take a look at Angular's limitTo filter.
Use an input with type="number" and an max=4 attribute:
<input type="number" max="4" name="input" ng-model="example.value">
Ref. https://docs.angularjs.org/api/ng/input/input%5Bnumber%5D
how are you applying the behavior with the numbers? I ask because maybe you could try to follow the same pattern. Otherwise, I think there are more than one option according to your needs. For instance, if the user introduces one number greater than 4, what should be the expected behavior? Return an error, block and donĀ“t write anything in the input,...
Depending on it, you could choose to add $parsers to the ngModelController or simply block the default behavior of the key by checking what is the key that has been pressed.

Unable to use ng-minlength for input with custom directive in Angular

I've based a phone number formatting directive on this gist. Everything generally works great. But if I add a ng-minlength or ng-maxlength validation requirement, the input won't accept any input at all.
.directive('phonenumberDirective', ['$filter', function($filter) {
function link(scope, element, attributes) {
scope.inputValue = scope.phonenumberModel;
scope.$watch('inputValue', function(value, oldValue) {
value = String(value);
var number = value.replace(/[^0-9]+/g, '');
scope.phonenumberModel = number;
scope.inputValue = $filter('phonenumber')(number);
});
}
return {
link: link,
restrict: 'E',
scope: {
phonenumberPlaceholder: '=placeholder',
phonenumberModel: '=model'},
template: '<input ng-model="inputValue" type="tel" id="phone" name="phone" ng-minlength="7" class="phonenumber form-control" placeholder="{{phonenumberPlaceholder}}" required /> '
}
}]);
HTML:
<label class="control-label" for="phone">Phone</label>
<phonenumber-directive placeholder="'(000) 000-0000'" model='contactForm.contact.phone'></phonenumber-directive>
<span ng-show="myForm.phone.$error.required && !myForm.phone.$untouched
|| myForm.phone.$error.required && !myForm.phone.$untouched
|| myForm.phone.$error.minlength && !myForm.phone.$untouched" class="help-block">
Enter your phone number</span>
If I understand your question correctly, this behavior is expected. Your ng-model won't be updated if the input does not pass through the validation pipeline.
In this case, you won't see your watcher get fired until ng-minlength is met.
As an aside, you may want to consider using ngModelController on an attribute-level directive (yours is an element directive) as a more "Angular" way to maintain differences between the view value and its underlying model value. You are currently updating inputValue inside a watcher that is looking for updates to inputValue, which may lead to unexpected behavior.

Setting ngTrueValue and ngFalseValue to numbers

Update: question is obsolete for latest Angular version, see tsh's comment on this post
I have bound a checkbox to a value:
<input type="checkbox" ng-model="checkbox" ng-true-value="1" ng-false-value="0" />
The value of the checkbox is set to 1 in the controller:
function Controller($scope) {
$scope.checkbox = 1
}
However, initially the checkbox does not appear checked. If I change the initial value of $scope.checkbox to "1", it does. (jsfiddle demo)
I have tried all kinds of variations:
ng-true-value="{{1}}"
ng-true-value="{{Number(1)}}"
ng-true-value="{{parseInt('1')}}"
None of them work. How can I make angular treat the arguments as a number?
You can use ngChecked, If the expression is truthy, then special attribute "checked" will be set on the element
<input type="checkbox"
ng-model="checkbox"
ng-true-value="1"
ng-false-value="0"
ng-checked="checkbox == 1" />
And you can use $scope.$watch to convert it to number
$scope.$watch(function(){
return $scope.checkbox;
}, function(){
$scope.checkbox = Number($scope.checkbox);
console.log($scope.checkbox, typeof $scope.checkbox);
},true);
DEMO
I have created directive for that, seems to work fine:
angular.module('app').directive('cdTrueValue', [function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(v){
return v ? scope.$eval(attrs.cdTrueValue) : scope.$eval(attrs.cdFalseValue);
});
ngModel.$formatters.push(function(value) {
return value === scope.$eval(attrs.cdTrueValue);
});
}
};
}]);
Usage:
<input type="checkbox" ng-model="checkbox" cd-true-value="1" cd-false-value="0" />
DEMO
HTML attributes do not have any types. They can not contain anything else, then a string, so it is always a string. End of story.
You can not differentiate between between 1 and "1" in an HTML attribute. Angular tries to keep up with that, so only strings will work.
The first approach above is great. That's works fine. You can also use ng-change directive if you need use dynamic model (e.g. linked with ID or number - in case you wanna work with ID you don't know ahead). Just pass model as parameter: ng-change="fooBar(model[ID])" , catch in controller function and use Number(model[ID]) re-type. That's convert true as 1, false as 0 and you can work with this.

AngularJS - Give checkbox an integer?

I was able to see true or false and return strings in checkboxes with ng-true-value and ng-false-value, but in additional, I want to give the checkbox an integer and if it's checked, it returns an integer.
Which should be similar to when I get a value from a selectbox: http://jsfiddle.net/PuDRm/
But I can't seem to get the same idea in a checkbox: http://jsfiddle.net/PuDRm/1/
<input type="checkbox" ng-model="testc" ng-true-value="Yes" ng-false-value="No" ng-change="processtest()" /> Yes
I'm a total newbie and trying to understand AngularJS.
It sounds like you are trying to bind to two separate values with the checkbox.
In the select the view is the name you gave e.g. 'test1', and the model is the number, e.g. '1'. For the checkbox, the view is a check or a blank square and the model is Yes/No (or whatever you want to put in the ng-true-value and ng-false-value). There's no room to have it produce a number too.
It would be simpler to let the checkbox model be the default (boolean) type by omitting the ng-true-value and ng-false-value attributes. You can then display the number and text based on this like in this updated fiddle: http://jsfiddle.net/D5DGf/1/
The {{ ... }} bindings take care of updating when the function values change, so you don't need to use ng-change either.
What was wrong with the original checkbox fiddle?
In the processtest function you are taking the model (Yes/No) and changing it to always be either 8 or 1. The checkbox (in fact, ngModel) doesn't understand this as it expects to always see Yes/No. As it doesn't know what to do, it falls back to being unchecked.
This is why the checkbox in the original fiddle is uncheckable.
If you still want to set use a number for your model and checbox value, you could do it with a custom directive to parse the string back to integer.
Demo: http://jsfiddle.net/qw5zS/
html
<input type="checkbox" ng-model="test" parse-int ng-true-value="1" ng-false-value="0" />
js
app.directive('parseInt', [function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
controller.$formatters.push(function (modelValue) {
console.log('model', modelValue, typeof modelValue);
return '' + modelValue;
});
controller.$parsers.push(function (viewValue) {
console.log('view', viewValue, typeof viewValue);
return parseInt(viewValue,10);
});
}
}
} ])
But this might not be a good practice using checkbox, you should stay with the default behavior and use a boolean, then format the view like you want, but keep your data clean.
If you change the column in database from integer to char, it works with
<input type="checkbox" ng-model="testc" ng-true-value="1" ng-false-value="0" ng-change="processtest()" /> Yes
Here is the solution which worked best in my trials :
<input type="checkbox"
ng-true-value="{{ 1 | json }}" ng-false-value="{{ 0 | json }}"
ng-model="myVariable">
Another approach without the needs of ng-model, ng-true-value and ng-false-value. Let's keep those the way they are.
js
angular.module('whateverModule')
.directive('toggleInt', function () {
function link ($scope, $element, attr) {
$element.on('click', function () {
$scope.$apply(function() {
$scope.toggleModel = +!$scope.toggleModel;
});
});
$scope.$watch('toggleModel', function (value) {
$element.prop('checked', !!value);
});
}
return {
restrict: 'A',
scope: {
toggleModel: '='
},
link: link
};
});
html
<input type="checkbox" toggle-int toggle-model="intModel">
<span>Value: {{intModel}}</span>
What I ended up doing was just using an if statement on the controller.
Example:
$scope.status = ($scope.status === 1 ? true : false);

Resources