AngularJS: SetValidity within an ng-repeat - angularjs

I want to check that an input value is valid, (i.e. if someone is spending at least 25 cents on a candy from a list of candies), and if not, tag that input as $invalid, so the form doesn't get submitted.
<form novalidate name="candyForm">
<div ng-repeat="candy in candies">
<input name="candyCost" type="text" ng-model="candy.cost" required>
<div class="error" ng-show='checkEnoughMoney()'>You only have 1 dollar to spend</div>
<div class="error" id="candyError{{$index}}">You must spend at least 25c per candy</div>
</div>
</form>
The checkEnoughMoney() is:
$scope.checkEnoughMoney = function() {
var total = 0;
for(var i = 0; i < $scope.candies.length; i++) {
var amount = parseFloat($scope.sweets[i].cost) || 0;
total = total + amount;
if((parseFloat(amount) >= 25) && (parseFloat(amount) <= 100)) {
$("#candyError" + i).hide();
}
else {
$("#candyError" + i).show();
}
}
if(total > 100) {
$scope.candyForm.candyCost.$setValidity('candyForm.candyCost',false);
return true;
}
else {
$scope.candyForm.candyCost.$setValidity('candyForm.candyCost',true);
return false;
}
};
Setting the $scope.candyForm.candyCost to true or false works here as it affects all the instances if candies, which is great, as it needs to. But how do I make the single instance invalid if the person has entered less than 25 cents or more than 100 cents?
As you can see, I have cheated to make the 25>=cost>=100 messages show when they should, but the form is still submitting, as the input is not being set to invalid. If I try $scope.candies[index].setValidity("cost", false), it throws an error, as the parent scope can't access the scope inside the ng-repeat. Is there any way to get around this?

Here's an example of handling forms in Angular that should take care of your problem.
http://docs.angularjs.org/cookbook/advancedform
I prefer to setup a controller fn to handle requests and pass those through a service.

Related

ParsleyJS Custom Math Validators

I've successfully adapted parts of ParsleyJS to my needs in my form. Now I need to make some custom math validators, but I am struggling to figure out why my validators are not working.
What I need to accomplish:
Input 1: x
Input 2: can not be more than 10 different from x
an example form:
<form id="demo-form" data-parsley-validate="">
<label for="input1">Input 1</label>
<input type="text" class="form-control" id="input1" name="input1" required>
<label for="input2">Input 2</label>
<input type="text" class="form-control" id="input2" name="input2" required data-parsley-not-more-than="input1" data-parsley-trigger="keyup" data-parsley-validation-threshold="0">
<input type="submit" class="btn btn-default pull-right">
</form>
from the custom validator demo example I figured it'd be solved pretty easily like so:
window.Parsley.addValidator('notMoreThan', {
validateNumber: function(value, requirement) {
return (value - requirement) <= 10;
},
requirementType: 'integer',
messages: {
en: 'This value can not be more than 10 different from %s'
}
});
but.. Uncaught Requirement is not a integer: "input1"
fine. we'll change to a string then.
window.Parsley.addValidator('notMoreThan', {
validateNumber: function(value, requirement) {
return (requirement - value) <= 10;
},
requirementType: 'string',
messages: {
en: 'This value can not be more than 10 different from %s'
}
});
but this always returns false, validation fails, whatever the input is.
then I look at the extras (greater than, less than or equal to) in the src/extra directory and they do this:
// gt, gte, lt, lte, notequalto extra validators
var parseRequirement = function (requirement) {
if (isNaN(+requirement))
return parseFloat(jQuery(requirement).val());
else
return +requirement;
};
// Greater than or equal to validator
window.Parsley.addValidator('gte', {
validateString: function (value, requirement) {
return parseFloat(value) >= parseRequirement(requirement);
},
priority: 32
});
So I guess, with my limited javascript knowledge, that they "interpret" the requirement value to return the right string if it's "not a number".
So, I try the same approach.
// gt, gte, lt, lte, notequalto extra validators
var parseRequirement = function (requirement) {
if (isNaN(+requirement))
return parseFloat(jQuery(requirement).val());
else
return +requirement;
};
// my not more than 10 different validator
window.Parsley.addValidator('notMoreThan', {
validateString: function (value, requirement) {
return ( parseFloat(value) - parseRequirement(requirement) ) <= 10;
},
priority: 32
});
But this always returns false as well.
I'm just at a complete loss. It may be my lack of javascript skills.. Hope this answer doesn't get downvoted for that. I'm trying to learn as best I can.
In conclusion, I need a solution to craft custom validators with simple math validations depending on fields. "Field B can be no more than X different from Field A" "Field D can not differ more than f from ((Field C divided by x) minus y)" and so on so on.
Hope someone can help me out.
I found out the solution, hope it helps people who face similar issues, as documentation is lacking for newbies in this regard.
window.Parsley.addValidator('notMoreThan', {
validateNumber: function(value, requirement) {
// requirement is passing the id of the input 1 so ve have to obtain the value of it
var requirement_value = $('#'+requirement).val() ;
return value - requirement_value <= 10 ;
},
requirementType: 'string',
messages: {
en: 'This value can not be more than 10 different from %s'
}
});
in order to make this work, we have to obtain the value of the requirement first. This is what was lacking.

Trying to validate that at least one checkbox is checked angularJS

Trying to figure out the best way to stay on the same page alerting the user if they have failed to check at least one checkbox.
HTML:
<div class="col3">
<input type="checkbox" ng-model="$parent.value5" ng-true-value="'Togetherness'" ng-false-value="">
<span class="checkboxtext">
Togetherness
</span><br>
<!--<p>We value our people and recognize that <strong>Together</strong> we achieve superior results.</p><br>-->
<div class="col3">
<a ui-sref="form.submit">
<button name="button" ng-click="SaveValue()">Continue</button>
</a>
Back-end angularJS to check if one of the boxes was checked-
$scope.SaveValue = function () {
var valueStatus = [];
if ($scope.value1 === "Methodical")
{
valueStatus.push($scope.value1);
}
if ($scope.value2 === "Relentless")
{
valueStatus.push($scope.value2);
}
if ($scope.value3 === "Togetherness")
{
valueStatus.push($scope.value3)
}
if ($scope.value4 === "Excellent") {
valueStatus.push($scope.value4)
}
if ($scope.value5 === "Ingenious") {
valueStatus.push($scope.value5)
}
return valueStatus
};
Basically I'm wanting to make an array of these values and then return it. However, I want the user to check at least one box. I've tried redirecting back to the page if valueStatus[0] == null. However, I don't think this is the best way to validate and it does not work completely how I think it ought to.
The way I solve this is putting validation on the length of array (valueStatus in your case) with hidden number input. The input will have min validation on. So, if user fails to check at least one, the form is not submitted;
<input type="number" name="valueStatus" ng-model="valueStatus.length" min="1" style="display: none">
Then, you can use normal validation on valueStatus that is available on the form model
myFormName.valueStatus.$valid
This way, most of the logic is put into the template, which is called angularjs way ;)
UPDATE
Forgot to mention:
You need to update the list of checked values on on-change checkbox event
<input type="checkbox" ng-model="checkboxValue1" on-change="updateValueStatus(checkboxValue1)">
<input type="checkbox" ng-model="checkboxValue2" on-change="updateValueStatus(checkboxValue2)">
and in controller
$scope.updateValueStatus = function(value){
var indexOf = $scope.valueStatus.indexOf(value);
if(indexOf < 0) {
$scope.valueStatus.push(value);
} else {
$scope.valueStatus.splice(indexOf, 1);
}
}
Hope it will help people with the same issue
simply just check the valueStatus length is equal to 0 or not
$scope.SaveValue = function () {
var valueStatus = [];
if ($scope.value1 === "Methodical")
{
valueStatus.push($scope.value1);
}
if ($scope.value2 === "Relentless")
{
valueStatus.push($scope.value2);
}
if ($scope.value3 === "Togetherness")
{
valueStatus.push($scope.value3)
}
if ($scope.value4 === "Excellent") {
valueStatus.push($scope.value4)
}
if ($scope.value5 === "Ingenious") {
valueStatus.push($scope.value5)
}
if (valueStatus.length === 0 ) {
console.log('please select atleast one select box')
}
return valueStatus
};
Edited
remove the ui-sref tag and change the state inside your click function
<button name="button" ng-click="SaveValue()">Continue</button>
in the saveValue function add this
if (valueStatus.length === 0 ) {
console.log('please select atleast one select box')
}else{
$state.go('form.submit') // if atleast one selected then the page will change
}

Based on Text field automatically fillup in the progress in Ionic angularjs

I need to show progress bar when i entered the fields.
Based on fields fillup automatically need to show the proress bar using angularjs in ionic.
I made the following codepen:
http://codepen.io/anon/pen/ZBBGgj
You need to track the progress based on the validation of the input.
function validateInput(input, arrayLength) {
console.log(input);
if (!input.validated && input.model.length > 3) {
vm.validationProgress = vm.validationProgress + (100 / arrayLength);
input.validated = true;
console.log(vm.validationProgress);
} else if (input.validated && input.model.length <= 0) {
input.validated = false;
vm.validationProgress = vm.validationProgress - (100 / arrayLength);
}
}
This code can be improved upon, and you should probably find a better solution to it, but it should point you in the right direction.
If an input is validated = true, I color the progressbox for that input green.
<div ng-repeat="input in vm.inputfields" ng-class="{ 'validated' : input.validated }" class="validation-item">

How can i count the number of errors on Form?

FIDDLE
How can i count the number of errors made on form ?
HTML
<div ng-show="form.$submitted && form.$invalid">
Sorry but 3 errors have been made.
</div>
One way you could do this by using the specific count of a specific error criteria, required, pattern etc.. that are available as a part of form's $error[prop] array. In your case you could try using form.$error.required.length:-
<div ng-show="form.$submitted && form.$invalid">
Sorry but {{form.$error.required.length}} errors have been made.
</div>
Demo
You could add a function on the controller which can determine the number of errors on the form and return it, and use it in the view to display the total error count.
$scope.numberoferrors=function(form){
var count = 0,
errors = form.$error;
angular.forEach(errors, function(val){ if(angular.isArray(val)) { count += val.length; } });
//Object.keys(errors).forEach(function(key){ count += errors[key].length }); //get count of all error categories from form
return count;
};
Demo

AngularJs form validation - manage custom errors priority to show only one error with the ng-show directives

here is my first question on this awesome forum.
my need is to warn the user why the number he enters is invalid, but I want to print only one message at each time. I've implemented a solution but it's not really easily evolutive.
Here is my HTML code :
<input type="number" name="amountReceived" class="styled" data-ng-model="cashAmountReceived" required>
<div class="error" data-ng-show="cashPaymentForm.amountReceived.$error.required && cashPaymentForm.submitted">Valid amount required</div>
<div class="error" data-ng-show="cashPaymentForm.amountReceived.$error.notEnought && cashPaymentForm.submitted">It's not enought</div>
<div class="error" data-ng-show="cashPaymentForm.amountReceived.$error.negatif && cashPaymentForm.submitted">Positive value only</div>
and here is my Controller code :
$scope.$watch('cashAmountReceived', function() {
if(angular.isNumber($scope.cashAmountReceived)){
var tmp = $scope.cashAmountReceived.toString();
tmp = tmp.replace(/(\d{0,9})+\.(\d{0,2}).*/,'$1.$2');
$scope.cashAmountReceived = parseFloat(tmp);
if( $scope.cashAmountReceived < 0){
$scope.cashPaymentForm.amountReceived.$setValidity('negatif', false);
$scope.cashPaymentForm.amountReceived.$setValidity('notEnought', true);
}
else{
$scope.cashPaymentForm.amountReceived.$setValidity('negatif', true);
if($scope.cashAmountReceived < $scope.totalProductPrice){
$scope.cashPaymentForm.amountReceived.$setValidity('notEnought', false);
}
else{
$scope.cashPaymentForm.amountReceived.$setValidity('notEnought', true);
}
}
}
else{
$scope.cashPaymentForm.amountReceived.$setValidity('notEnought', true);
$scope.cashPaymentForm.amountReceived.$setValidity('negatif', true);
}
});
I've to manually manage validity errors to make sure that only one will be printed thanks to the ng-show directives in my HTML page. I'd like to implement a easily evolutive solution, in case I need to add more validation criteria.
I think about to make my own directive with a priority management system on my custom errors and compatible with the defaults errors possibilities, but I don't know how to proceed.
Or maybe I can leave the process in the controller and create only one custom error called custom and define a scope variable called errorReason whitch will contain the appropriate warning message
I'll have something like that in my HTML code :
<input type="number" name="amountReceived" class="styled" data-ng-model="cashAmountReceived" required>
<div class="error" data-ng-show="cashPaymentForm.amountReceived.$error.custom && cashPaymentForm.submitted">{{errorReason}}</div>
What do you guys think about it?
I apologize if my english is not correct.

Resources