angularjs additional form validation rules (not input field validation) - angularjs

What's the angular way to add validation rules to a form, that do not belong to a single input field, but on multiple field values together?
E.g.:
Check if at least one of x checkboxes is checked
Check if the sum of multiple number inputs is equal to a given Number
...
It would be nice if the errors can be shown with ng-messages. I'm using angular 1.3.10.

There's no built-in functionality, but it requires little effort.
ng-messages does not depend on anything specific. It just needs an object whose keys can be referenced by ng-message. The simplest solution would be to hook into the submit event (which you probably do anyway) and run additional validation.
<form ng-submit="post()" name="myForm">
<input type="checkbox" name="one" ng-model="one" />
<input type="checkbox" name="two" ng-model="two" />
<input type="submit" />
<div ng-messages="formErrors">
<p ng-message="tooMany">Please, check one checkbox only</p>
<p ng-message="required">Please, check a checkbox</p>
</div>
</form>
On submission the function post() is called which adds any error to the object formErrors:
$scope.post = function() {
...
var hasErrors = false;
$scope.formErrors = {
};
if ($scope.one && $scope.two) {
$scope.formErrors.tooMany = hasErrors = true;
}
if (!$scope.one && !$scope.two) {
$scope.formErrors.required hasErrors = true;
}
if (hasErrors) {
return;
}
}

Related

How to apply ng-required in MultiSelect?

I am using searchable-multiselect in angular js, ng-required=true is not working in multiselect.How to apply ng-required in MultiSelect ?
<searchable-multiselect display-attr="name" selected-items="users.user" all-items="allusers" ng-required=true
add-item="add(item,user)" remove-item="remove(item,user)" ng-model="dropdownValues">
You can only apply ng-required onto directives that require ng-model. Looking into the searchable-multiselect directive, it doesn't require ng-model nor does it have any required configuration.
The easiest way to do form validity on this would be to add a hidden input that contains something you can do validity on. In this case you can use the model object that you're storing the data on. In the example below, we're checking the length of the selected items and requiring there be a minimum of 1 entry.
<input
style="display: none;"
type="number"
ng-model="dropdownValues.length"
ng-required="true"
min="1" />
Working Plunkr: http://next.plnkr.co/edit/gkxUvPVK0NkdOewj
Use the following :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div
multi-select
input-model="batch_timing.days"
output-model="resultData"
button-label="acronym"
item-label="acronym symbol name"
tick-property="ticked"
helper-elements="all none reset"
required name="days">
</div>
<button ng-click="validation()">submit</button>
$scope.resultData = [];
$scope.validation = function () {
if($scope.resultData === null || $scope.resultData == '') {
return false; // not validated
} else {
return true; // validated
}
}

Elegant way in Angular to enable submit if all child forms but the last are valid

In the simple Angular app I'm working on there is a parent form with various child forms that are created from an ng-repeat. I'd like a submit button to be tied to the parent form's $valid property OR some other simple way to enable the submit button when the form is what I consider to be valid. However, due to the user workflow a new child form is added after the fields of the last child form are completed. Thus, even a perfect form's last row is always empty & thus invalid (as there are required fields). Any suggestions on how to handle enable/disable of a submit button in this situation? I've created a fiddle that shows the issue. There is a submit button linked to the parent form's $valid, which does not show up unless the last form (row) is valid. Then there's a second submit button, whose enabled property I control by explicitly looking at all child forms and setting a scope variable to true or false based on my requirements. I think this solution is inelegant and there's got to be a better way.
https://jsfiddle.net/godinger/r5yx5z4b/
Here's the HTML form:
<div ng-app="myApp" ng-controller="myCtrl">
<pre>Parent Form Valid: {{parentForm.$valid}}</pre>
<ng-form name="parentForm">
<div ng-repeat="person in people">
<ng-form name="childForm" novalidate>
<input name="firstName"
required
ng-model="person.firstName"
ng-init="person.form=childForm"/>
<input name="lastName"
required
ng-model="person.lastName"
ng-init="person.form=childForm"/>
<span>Valid: {{childForm.$valid}}</span>
</ng-form>
</div>
<button ng-submit ng-disabled="parentForm.$invalid">
Submit
</button>
<button ng-submit ng-disabled="!enableSubmit">
Workaround Submit
</button>
</ng-form>
</div>
And here's the Angular code:
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.enableSubmit = false;
$scope.people = [
{firstName: 'John', lastName: "Adams"},
{firstName: 'Alex', lastName: 'Hamilton'},
{firstName: '', lastName:''}];
$scope.$watch(updateSubmit);
function updateSubmit(){
if (!$scope.people){
$scope.enableSubmit = false;
return;
}
var numberOfPeople = $scope.people.length;
for (var i=0; i<numberOfPeople-1; i++){
var personForm = $scope.people[i].form;
if (personForm.$invalid){
$scope.enableSubmit = false;
return;
}
}
var lastPerson = $scope.people[numberOfPeople-1];
var lastPersonForm = lastPerson.form;
if (lastPersonForm.$valid){
$scope.enableSubmit = true;
return;
}
if (lastPerson.firstName || lastPerson.lastName){
$scope.enableSubmit = false;
return;
}else{
$scope.enableSubmit = true;
return;
}
}
});
I'm not sure that your implementation makes the most sense, but if want you want to do is provide "different html" based on the last element in ng-repeat, the simplest way is to use the $last element local variable. There are a number of ways to do this...but here is the simplest answer to your question:
<ng-form ng-if="!$last" name="childForm" novalidate>
<input name="firstName" placeholder="First name"
ng-model="person.firstName"
ng-init="person.form=childForm"/>
<input name="lastName"
required placeholder="First name"
ng-model="person.lastName"
ng-init="person.form=childForm"/>
<span>Valid: {{childForm.$valid}}</span>
</ng-form>
<div ng-if="$last">
Do Other Logic / Show other stuff (this could even be repeat all the form elements again, but remove all of the 'required' properties)
</div>

parsley js - conditional required if checkbox checked

Is there an easy way with parsleyjs to make a field required depending on another field?
See my js fiddle here http://jsfiddle.net/marksteggles/wbhLq0t4/1/
<form data-parsley-validate="true">
<div class="form-group">
<label>
<input name="request_signature" type="checkbox" />Require signature</label>
<div class="request_signature_fields">
<textarea class="form-control required" name="signature_reason" rows="3"></textarea>
</div>
</div>
<input class="btn btn-success" name="commit" type="submit" value="Send" />
</form>
Minimally as of 2.2.0 you can create a custom validator:
window.Parsley.addValidator("requiredIf", {
validateString : function(value, requirement) {
if (jQuery(requirement).val()){
return !!value;
}
return true;
},
priority: 33
})
This gets applied in such a way:
<textarea
class="form-control required"
name="signature_reason"
rows="3"
data-parsley-validate-if-empty="true"
data-parsley-required-if="#my-field-to-check"
></textarea>
Explanation
data-parsley-required-if is the custom validator we just defined. It takes any arbitrary jQuery selector and if that field contains a non-falsy value it ensures that this field is not empty.
data-parsley-validate-if-empty is needed to ensure that the field is being validated at all, because Parsley does not validate empty non-required fields by default.
More data on custom validators here: http://parsleyjs.org/doc/index.html#custom
There is no easy way yet (see this and this).
You can either toggle the attribute required with Javascript, or listen to the right parsley events on one field and check the other field.
Just incase anyone else is trying to work this out. The best way does seem to be altering the required attribute then clearing the values.
I used this:
HTML:
<input id="checkbox-id" type="checkbox">
<div id="conditional-inputs" style="display:none;">
<input type="text" name="somename" />
<input type="text" name="othername" />
<input type="text" name="onemoreforluck" />
</div>
jQuery:
$("#checkbox-id").change(function() {
if(this.checked) {
$('#conditional-inputs').slideDown();
/* use .slideDown to display conditional input block */
$("#conditional-inputs :input").prop('required', true);
/* set required attribute on all inputs inside conditional area */
}
else{
$('#conditional-inputs').slideUp();
/* use .slideUp to hide conditional input block */
$("#conditional-inputs :input").prop('required', false).val('');
/* remove required attribute on all inputs and empty values of inputs */
}
})
I realise that this question was asked and answered in 2012, and is most likely related to the ParsleyJS v1, while the most recent version at the time of writing this is v2.2.0. However I had to do some work on an old form that used v1 and I found that conditionals are possible (with a little bit of jQuery). So here's to anyone who might still need this.
You can dynamically add and remove form elements and constraints (read: validation rules) using the following:
$('#form').parsley('addItem', '#input_id');
$('#form').parsley('removeItem', '#input_id');
$('#input_id').parsley('addConstraint', '{ required: true }');
$('#input_id').parsley('removeConstraint', 'required');
So using jQuery listeneners for when the checkbox changes we can execute this kind of code which will add the signature field as a required field. Here it is in action for the question.
< script src = "js/parsley-v1.js" > < /script>
<script>
$('#request_signature').on('click', function() {
if($(this).is(':selected')) {
$('#signature_form').parsley('addItem', '#signature_reason');
$('#signature_reason').parsley('addConstraint', { required: true });
} else {
$('#signature_reason').parsley('removeConstraint', 'required' });
$('#signature_form').parsley('removeItem', '#signature_reason');
}
});
</script >
<form id="signature_form" data-parsley-validate="true">
<div class="form-group">
<label>
<input id="request_signature" name="request_signature" type="checkbox" />Require signature</label>
<div class="request_signature_fields">
<textarea id="signature_reason" class="form-control" name="signature_reason" rows="3"></textarea>
</div>
</div>
<input class="btn btn-success" name="commit" type="submit" value="Send" />
</form>
You can also hide the parts that are not required anymore, or disable the fields that are not needed, and add [disabled] and :hidden to the excluded Parsley option.
{
excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden], [disabled], :hidden',
}
NB: you don't need to hide each field, hiding a parent div is enough.
I found a good example that I forked here
➡️ http://jsfiddle.net/capripot/xoaLs4bt/
This should be possible with the great little Parsley addon plugin found here: http://themonk.github.io/parsely-conditions/
I found the shortest method -
$('input[type=radio][name=nlcsu]').change(function() {
// I am checking for a Radio button
if (this.value == 1) {
$("#nlcsu_post").attr('required', '1');
$("#nlcsu_year").attr('required', '1');
} else if (this.value == 0) {
$("#nlcsu_post").removeAttr('required');
$("#nlcsu_year").removeAttr('required');
}
});

How to use Angular input fields email validation inside controller?

I'm trying to validate a variable as email inside Angular controller.
var valid = $filter('email')($scope.email);
The email filter doesn't exists, generates "unknown provider error". What's the correct way to access email validation from inside the controller?
Thanks.
Later edit: don't put me to create a custom filter, it must be a way using angular validation.
You can create a hidden input type email:
<input type="email" hidden id="emailValidator" required ng-model="x" />
Then in js set the value to that input and check validity:
var validator = $('#emailValidator')[0];
validator.value = "someemail#tovalidate.com";
return validator.checkValidity();
Also this documentation could be helpful: https://docs.angularjs.org/guide/forms
You could use form and prevent form submission by adding ng-disabled to the submit button:
<form name="form">
<input type="email" ng-model="email" name="email" required/>
<button type="submit"
ng-disabled="form.$invalid">Submit</button>
</form>
{{form.email.$valid}}
As the point of validation is to prevent submission and show error messages. I think it's enough to do it there instead of controllers where you handle your business logic.
DEMO
You can write your own filter:
angular.module(/**some module description here**/).
filter('email',function(){
var validateEmail = function(email) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
return function(input){
return validateEmail(input);
};
});
Regular expression is borrowed from here

Don't record invalid values with ng-model

I really like how the ng-model attribute binds directly to my model and users get instant feedback on their changes. For my use case that's perfect. However, I don't want invalid values to be put into the model where they can throw a wrench into the calculations. I somehow want the model to only be updated if the value in the form control is valid. For invalid values, it's fine for the control value to change while the model value stays fixed.
If I change the source of angular (1.2rc) NgModelController's $setViewValue implementation:
this.$setViewValue = function(value) {
...
if (this.$modelValue !== value) {
this.$modelValue = value;
...
}
};
To this:
this.$setViewValue = function(value) {
...
if (this.$modelValue !== value && this.$valid) {
this.$modelValue = value;
...
}
};
It seems to do exactly what I want, however I don't know how to do this in a proper way. What's the right way to change this behavior? Or are my attempts doomed to failure for some reason?
Update: Added example.
For example look at http://jsfiddle.net/FJvgK/1/ HTML:
<div ng-controller="MyCtrl">
{{validNumber}}
<form>
<input
type="number"
ng-model="validNumber"
required
min="10"
max="20"
/>
</form>
</div>
And the JS:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.validNumber = 15;
}
The number shows properly for values between 10 and 20, but I want it so that if you suddenly type '8' into the box, or delete the second digit leaving '1' the last valid number still shows above. That is, the model always has a valid value, even if the control does not.
I believe the default behaviour of AnugularJS validators are not to update the model if the value passed is invalid. If you look at the developer guide and go through Custom Validation these samples also show that the model is not update or is cleared on invalid value provided in the UI
This is default behaviour, but, you can modify this using ngModelOptions directive
<input
type="number"
ng-model="validNumber"
required
min="10"
max="20"
ng-model-options="{ allowInvalid: true }"
/>
Documentation: https://docs.angularjs.org/api/ng/directive/ngModelOptions See the section 'Model updates and validation'
As Chandermani said, it is the default behavior, here is a example that shows it in action :
<form name="myform">
<input type="text" name="myinput" ng-model="myvalue" ng-minlength="4" required>
</form>
Is the input valid ? {{ myform.myinput.$valid }} <br />
Input's value : {{ myvalue }}
{{ myvalue }} doesn't show anything until you write at least 4 characters in the input.
Best Regards.
EDIT
If you need a default value, I guess you could break down your value into 2 values, using a computed value :
var validNumber = 15;
$scope.validNumber = function () {
if ($scope.myform.myNumber.$valid) return $scope.myNumber;
else return validNumber;
};
I set up an example here : http://jsfiddle.net/7vtew/1/

Resources