model got 'undefined' when $setValidity set to false - javascript

I have a form with one input field, and I validate that input when the value changes by using $setValidity .But the problem is when $setValidity set to false (invalid) the model is no longer updating, it holds value 'undefined' .
Here is my HTML :
<form name="frmEnrollPaymentPlan" novalidate autocomplete="off">
<div class="form-group" ng-class="{'has-error':(frmEnrollPaymentPlan.dwnAmt.$invalid && !frmEnrollPaymentPlan.dwnAmt.$pristine)||frmEnrollPaymentPlan.dwnAmt.$error.validateDownPaymentAmount}">
<label>Downpayment</label>
<input type="text" class="form-control" name="dwnAmt" ng-model="EnrollPaymentPlanViewModel.DownPaymentAmount" required ng-change="downPaymentChanged()" ng-model-options="{allowInvalid: true}">
<span ng-show="frmEnrollPaymentPlan.dwnAmt.$error.validateDownPaymentAmount" ng-class="{'error':frmEnrollPaymentPlan.dwnAmt.$error.validateDownPaymentAmount}">Cannot be less than down payment amount</span>
</div>
</form>
and Here is my javascript code:
$scope.downPaymentChanged = function () {
if (!isNaN($scope.EnrollPaymentPlanViewModel.DownPaymentAmount)) {
var downPaymentAmount = parseFloat($scope.EnrollPaymentPlanViewModel.DownPaymentAmount);
var minDownPaymentAmount = parseFloat($scope.EnrollPaymentPlanViewModel.MinDownPaymentAmount);
if (downPaymentAmount < minDownPaymentAmount) {
$scope.frmEnrollPaymentPlan.dwnAmt.$setValidity("validateDownPaymentAmount", false);
}
else {
$scope.frmEnrollPaymentPlan.dwnAmt.$setValidity("validateDownPaymentAmount", true);
}
}
}

Related

How get the Count of Empty Input fields?

How can I check the Number of Incomplete Input fields in Particular ID, (form1, form2).
If 2 input fields are empty, in i want a msg saying something like "Incomplete Input 2"
How is it Possible to do this in JS ?
<div id="form1">
<span>Number of Incomplete Input: 2</span>
<input type="text" value="">
<input type="text" value="">
</div>
<div id="form2">
<span>Number of Incomplete Input: 1</span>
<input type="text" value="Test">
<input type="text" value="">
</div>
This is the JS, which is working, i have have multiple JS with class named assigned to each inputs and get the value, but i need to make this check all the Input fields inside just the ID.
$(document).on("click", "#form1", function() {
var count = $('input').filter(function(input){
return $(this).val() == "";
}).length;
alert(count);
});
Your html structure, especially form structure is not correct, so you should first add some submit button to form that can be clicked. Then you can add event listener on form's submission. In the event handler you should select children inputs inside the form tag using $(this).children("input"). Now you can filter them.
$(document).on("submit", "#form1", function (e) {
e.preventDefault();
var count = $(this)
.children("input")
.filter(function (input) {
return $(this).val() == "";
}).length;
alert(count);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="form1">
<span>Number of Incomplete Input: 2</span>
<input type="text" value="">
<input type="text" value="">
<button type="submit">Submit</button>
</form>
This is the JS, which is working, if I have have multiple JS with class named assigned to each inputs and Im getting the value, but i have multiple JS for this to work.
How can i make this Simpler say like, when user clicks on Div, it only checks the input fields inside that div.
$(document).on("click", "#form1", function() {
var count = $('.input_field1').filter(function(input){
return $(this).val() == "";
}).length;
alert(count);
});
HTML
<div id="form1">
<span>Number of Incomplete Input: 2</span>
<input type="text" value="" class="input_field1">
<input type="text" value=""class="input_field1">
</div>
<div id="form2">
<span>Number of Incomplete Input: 1</span>
<input type="text" value="Test" class="input_field2">
<input type="text" value="" class="input_field2">
</div>
See snippet below:
It has commented and if you put some effort on it, you can have a jQuery plugin out of it.
(function () {
'use strict';
var
// this use to prevent event conflict
namespace = 'customValidation',
submitResult = true;
var
input,
inputType,
inputParent,
inputNamePlaceholder,
//-----
writableInputTypes = ['text', 'password'],
checkboxInputType = 'checkbox';
var
errorContainerCls = 'error-container';
// Add this function in global scope
// Change form status with this function
function changeFormStatus(status) {
submitResult = submitResult && status;
}
// Check if a radio input in a
// group is checked
function isRadioChecked(form, name) {
if(!form || !name) return true;
var radio = $(form).find('input[type="radio"][name="' + name.toString() + '"]:checked');
return typeof radio !== 'undefined' && radio.length
? true
: false;
}
function eachInputCall(inp, isInSubmit) {
input = $(inp);
inputType = input.attr('type');
// assume that we have a name placeholder in
// attributes named data-name-placeholder
inputNamePlaceholder = input.attr('data-name-placeholder');
// if it is not present,
// we should have backup placeholder
inputNamePlaceholder = inputNamePlaceholder ? inputNamePlaceholder : 'input';
if(!inputType) return;
// you have three type of inputs in simple form
// that you can make realtime validation for them
// 1. writable inputs ✓
// 2. checkbox inputs ✓
// 3. radio inputs ✕
// for item 3 you should write
// another `else if` condition
// but you should have it for
// each name (it was easier if it was a plugin)
// radio inputs is not good for realtime
// unchecked validation.
// You can check radios through submit event
// let make it lowercase
inputType = inputType.toLowerCase();
// first check type of input
if ($.inArray(inputType, writableInputTypes) !== -1) {
if(!isInSubmit) {
input.on('input.' + namespace, function () {
writableInputChange(this);
});
} else {
writableInputChange(inp);
}
} else if ('checkbox' == inputType) { // if it is checkbox
if(!isInSubmit) {
input.on('change.' + namespace, function () {
checkboxInputChange(this);
});
} else {
checkboxInputChange(inp);
}
}
}
// Check if an input has some validation
// (here we have just required or not empty)
function writableInputChange(inp) {
// I use $(this) instead of input
// to prevent conflict if selector
// is a class for an input
if('' == $.trim($(inp).val())) {
changeFormStatus(false);
// your appropriate message
// you can use bootstrap's popover
// to modefy just input element
// and make your html structure
// more flexible
// or
// if your inputs are in
// separate containers do
// somthing like below
inputParent = $(inp).parent();
if(!inputParent.children('.' + errorContainerCls).length) {
inputParent.append($('<div class="' + errorContainerCls + '" />').text('Please fill ' + inputNamePlaceholder));
}
} else {
changeFormStatus(true);
// I assume we have separate
// containers for each input
inputParent = $(inp).parent();
inputParent.children('.' + errorContainerCls).remove();
}
}
// Check if an checkbox is checked
function checkboxInputChange(chk) {
if(!$(chk).is(':checked')) {
changeFormStatus(false);
// if your inputs are in
// separate containers do
// somthing like below
inputParent = $(chk).parent();
if(!inputParent.children('.' + errorContainerCls).length) {
inputParent.append($('<div class="' + errorContainerCls + '" />').text('Please check ' + inputNamePlaceholder));
}
} else {
changeFormStatus(true);
// I assume we have separate
// containers for each input
inputParent = $(chk).parent();
inputParent.children('.' + errorContainerCls).remove();
}
}
$(function () {
var
form = $('#form'),
// you can change this selector with your classes
formInputs = form.find('> .input-group > input');
formInputs.each(function () {
eachInputCall(this);
});
form.submit(function () {
submitResult = true;
// check all inputs after form submission
formInputs.each(function () {
eachInputCall(this, true);
});
// Because of radio grouping by name,
// we should select them separately
var selectedGender = isRadioChecked($(this), 'gender');
var parent;
if(selectedGender) {
changeFormStatus(true);
parent = $(this).find('input[type="radio"][name="gender"]').parent();
parent.children('.' + errorContainerCls).remove();
} else {
changeFormStatus(false);
// I assume that all radios are in
// a separate container
parent = $(this).find('input[type="radio"][name="gender"]').parent();
if(!parent.children('.' + errorContainerCls).length) {
parent.append($('<div class="' + errorContainerCls + '" />').text('Please check your gender'));
}
}
if(!submitResult) {
console.log('There are errors during validations!');
}
return submitResult;
});
});
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="form">
<div class="input-group">
<input type="text" name="input1" data-name-placeholder="name">
</div>
<div class="input-group">
<input type="checkbox" name="input2" data-name-placeholder="agreement">
</div>
<div class="input-group">
<input type="radio" name="gender">
<input type="radio" name="gender">
</div>
<button type="submit">
submit
</button>
</form>

I'm trying to validate multiple HTML Form inputs with javascript, and change css for invalid ones, what is the best way to do this?

I'm trying to validate an HTML form, trying to check if answers are filled in, and an e-mail is an actual e-mail adress. I want to proceed when all fields are valid. When some fields are not valid, change the css in to another class (so it becomes red to show that it is wrong.)
I have tried to validate each input seperately, but i believe there should be an easier way. Can somebody show me?
Current HTML:
<div class="form-group" id="stage1">
<div class="row">
<input type="text" id="firstname" class="form-control" placeholder="Firstname*">
<input type="text" id="lastname" class="form-control" placeholder="Lastname*">
<input type="email" id="email" class="form-control" placeholder="E-mail*">
<input type="text" id="regnr" class="form-control" placeholder="Registration number">
</div>
</div
I can't use HTML default validation, since I have created a multi-step form.
Thanks in advance,
Brandon
You can iterate through inputs this will assist validating your messy items:
window.onload = () => {
const allInputs = document.querySelectorAll(".form-control"); // or you may assign custom class or select by input tag..
let isAllvaild = true;
allInputs.forEach((element) => {
if (!validateAll(element.value, element.type)) { isAllvaild = false; break; }
});
if (isAllvaild) {
afterValidation(); // to keep things clean
}
}
function validateAll(value, type) {
if (type === "text") {
} else if (type === "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,}))$/;
let ck = re.test(String(value).toLowerCase());
if (ck) {
// set errors here..
} else {
// maybe remove errors if added previously..
}
return ck;
} else if (type === "phone") {
} else if (type === "other") {
} // add whatever needed..
}
function afterValidation() {
// at this point each input contains valid data.. proceed to next step..
// document.querySelector("#my_id").classList.add("display-block");
// ..
}
you can validate based on their type, so i think u would have two functions, one for email and another one for text fields. for instance:
if(textValidation() && emailValidation()){
submit()
}
emailValidation(){
return email ? true : false
}
textValidation(){
return text ? true : false
}
What about that? It will let you loop through every input and you can also do some specific validations. I know, it is not the smartest function ever, but it can be useful. (ofc you should make some better checking for email pattern (regular expressions are good for that /^.+?#.+..+$/m) and registration number (regex could be cool for that too: /^[\d]*$/m)
function validateInputs ()
{
const inputs = document.querySelectorAll('div[class=row] input');
for (let index = 0; index < inputs.length; index++)
{
const input = inputs[index];
let valid = false;
if (input.value && input.value.trim() !== '')
{
//here you can add specific validations for each id, maybe you can also use switch here
if (input.getAttribute('id') === 'email')
{
//of course, email also need to validate, if dot is present, regular expression might be the best option
if (input.value.indexOf('#') !== -1)
{
valid = true;
}
}
else
{
valid = true;
}
}
if (!valid)
{
input.classList.add('error');
}
else
{
input.classList.remove('error');
}
}
};
window.addEventListener('load', function () {
document.querySelector('button').addEventListener('click', validateInputs)
});
input.error {
background-color: red;
}
<div class="row">
<input type="text" id="firstname" class="form-control" placeholder="Firstname*">
<input type="text" id="lastname" class="form-control" placeholder="Lastname*">
<input type="email" id="email" class="form-control" placeholder="E-mail*">
<input type="text" id="regnr" class="form-control" placeholder="Registration number">
</div>
<button>validate</button>
For fields like text you need to write your own validation, since it is totally up to you. But in case of fields like email or url you can use build in functions like the HTMLFormElement.checkValidity() method to see if the form contains a field that does not have a valid input, for example a input with type email and a value of foobar would return false from the validity check.
Then you can look inside the form and search for all inputs that are invalid with the :invalid selector in querySelectorAll(). It will return a NodeList with the invalid form elements inside of it.
const form = document.querySelector('form');
form.addEventListener('input', event => {
if (form.checkValidity() === false) {
const invalids = form.querySelectorAll(':invalid');
for (const input of invalids) {
console.log(`${input.id} is invalid`);
}
}
});
<form>
<input type="text" id="firstname" class="form-control" placeholder="Firstname*">
<input type="text" id="lastname" class="form-control" placeholder="Lastname*">
<input type="email" id="email" class="form-control" placeholder="E-mail*">
<input type="url" id="website" class="form-control" placeholder="Website*">
<input type="text" id="regnr" class="form-control" placeholder="Registration number">
</form>
You can use this code between a script tag :
const form = document.querySelector('form'); form.addEventListener('input', event => { if (form.checkValidity() === false) { const invalids = form.querySelectorAll(':invalid'); for (const input of invalids) { console.log(`${input.id} is invalid`); } } });
Or use a Bootstrap classes to validate your form

Validating a form when either a "select" OR "input" is required

I have a page containing multiple forms, all different, and when one is submitted I use the function below to gather all the inputs from that form with the class "required" and check for empty values:
function validateForm(form) {
var inputs = form.getElementsByTagName('input');
var selects = form.getElementsByTagName('select');
var errors = 0;
for (var i = 0; i < inputs.length; i++) {
if(inputs[i].classList.contains('required')) {
if(inputs[i].value === "") {
inputs[i].classList.add("warning");
errors++;
} else {
inputs[i].classList.remove("warning");
}
}
}
if(errors) {
return false;
} else {
return true;
}
}
If it finds an empty value, it adds the class "warning" which just gives the input a red border, then returns false so the form doesn't get submitted.
Here's where I'm running into trouble: Some forms contain a <select> and a text input, ONE of which must be filled in, but not both, as well as various other text inputs. I'm trying to figure out how to modify the above function to handle this.
Let's say the form is for adding a new product. The select is dynamically populated with existing product "categories" and the text input is for if the user wants to create a new category. Here's a simplified version of the form:
<form method = "post" onsubmit = "return validateForm(this)">
<div class = "form-group">
<label>Product Name</label>
<input class = "form-control required" type = "text" name = "product" />
</div>
<div class = "form-group">
<select class = "form-control required" id = "category" name = "category[]">
<option value = "">Select Existing Category</option>
<option value = "Shirts">Shirts</option>
<option value = "Shoes">Shoes</option>
<option value = "Pants">Pants</option>
</select>
</div>
<div class = "form-group">
<label>Create New Category</label>
<input class = "form-control required" type = "text" name = "category[]" />
</div>
<div class = "form-group">
<input class = "btn btn-primary" type = "submit" value = "Submit" />
</div>
</form>
Since I'm using a for loop to go through the inputs - the select and the input are not going to have the same index, so I can't do something like this:
if((selects[i].value === "" && inputs[i].value === "") || (selects[i].value !== "" && inputs[i].value !== "")) {
// add the warning class to both
}
I feel the answer lies somewhere in using the name attribute, i.e. compare selects.name and inputs.name, but how do I get around the differing index in the loop? And also, it should only make this comparison when the select is encountered anyway. It doesn't necessarily exist, depending on the form.
Basically, I need to modify my function to do this:
I. Gather all inputs and selects (if any - some forms will not) from a submitted form
II. Make sure none of the inputs with the "required" class are blank (unless there's a corresponding select, in which case see III below)
III. If there's a select, find the text input with the same "name" (not a requirement to have the same name, but I assume this is the right way to do it). One of them, but not both, must have a value. If both are blank, or both have a value, they should get the "warning" class;
Any help anyone can offer will be greatly appreciated!
Here's a function that do exactly what you want and can handle any form you want, as long as they have the same HTML structure.
Notes:
I recommend avoiding inline event listeners as much as you can, in
the snippet below I used addEventListener method to attach submit
event to all the forms in the document, you can change this to just
some specific forms if you want.
Instead of only adding a border to the required elements, I suggest
you also add some text to tell what the problem is.
// getting all forms in the page you can also get specific forms based on their class-name
var forms = document.getElementsByTagName('form'),
l = forms.length,
i = 0;
// adding submit submit event listener to the referenced forms
for(; i < l; i++) {
forms[i].addEventListener('submit', validateForm);
}
function validateForm(e) {
var els = this.querySelectorAll('input.required'),
len = els.length,
err = false,
c = 0,
inpName = '';
// checking if the form has a select, if so, allow only the select or the input to be filled
var isSelect = this.getElementsByTagName('select');
if(isSelect[0] !== undefined && isSelect[0] !== null) {
var inp = isSelect[0].parentNode.nextElementSibling.querySelector('input.required');
inpName = inp.name;
if((isSelect[0].value == '' && inp.value.trim().length === 0) || (isSelect[0].value != '' && inp.value.trim().length > 0)) {
err = true;
isSelect[0].classList.add("warning");
inp.classList.add("warning");
} else {
isSelect[0].classList.remove("warning");
inp.classList.remove("warning");
}
}
// iterate through the rest of the inputs and check for empty one, thus trimming them before checking
for(; c < len; c++) {
if(els[c].name !== inpName) {
if(els[c].value.trim() == '') {
err = true;
els[c].classList.add("warning");
} else {
els[c].classList.remove("warning");
}
}
}
// based on the error variable, either submit the form or cancel submission
(!err) ? this.submit():e.preventDefault();
}
.warning {
border: 2px solid red;
}
<form method="post">
<div class="form-group">
<label>Product Name</label>
<input class="form-control required" type="text" name="product" />
</div>
<div class="form-group">
<select class="form-control required" id="category" name="category[]">
<option value="">Select Existing Category</option>
<option value="Shirts">Shirts</option>
<option value="Shoes">Shoes</option>
<option value="Pants">Pants</option>
</select>
</div>
<div class="form-group">
<label>Create New Category</label>
<input class="form-control required" type="text" name="category[]" />
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
Hope I pushed you further.
You may get a message saying: "The custom error module does not
recognize this error." when you successfully submit the form from the
snippet above, that due to StackOverflow's restrictions as they
don't allow/server side code (StackOverflow doesn't let the form to
be submitted).

jQuery : How to do validation in jquery before submit the form?

I have a form bootstrap form like below
<form id="loginForm" method="post" action="" role="form" class="ajax">
<div class="form-group">
<label for="userName"></label>
<input type="text" class="form-control" id="usrName">
</div>
<div class="form-group">
<label for="passWrd"></label>
<input type="password" class="form-control" id="passWrd">
</div>
<div class="form-group">
<button class="btn btn-default" type="button" id="loginButton">Login</button>
</div>
I am doing form validation in my jquery as below. How do I call submit() method in my code? i.e how do I make ajax call to submit the form content after validation in the jQuery.
$(document).ready(function() {
function validateInput(id) {
if($("#"+id).val()==null || $("#"+id).val()=="") {
var div=$("#"+id).closest("div");
div.addClass("has-error");
return false;
} else {
var div=$("#"+id).closest("div");
div.removeClass("has-error");
div.addClass("has-success");
return false;
}
}
$(#loginButton).click(function() {
enter code here
if(!validateInput("userName"))
{
return false;
}
if(!validateInput("passWrd"))
{
return false;
}
});
});
How do i call $.ajax after i complete the validation in my above code?
P.S : I am not supposed to use any jquery plugin for the validation.
$('#loginForm').submit() will submit the form.
Try this:
$(document).ready(function() {
function validateInput(id) {
var element = $("#"+id);
var success = false;
if (element.val() == null || element.val().trim() == "") {
element.closest("div").addClass("has-error");
} else {
var div = element .closest("div");
div.removeClass("has-error");
div.addClass("has-success");
success = true;
}
return success;
}
$(#loginButton).click(function() {
if (validateInput("usrName")) {
$('#loginForm').submit()
}
});
});
<div ng-class="{ 'form-group has-error has-feedback' : datos.campo.$invalid && !datos.campo.$pristine, 'form-group has-success has-feedback' : datos.campo.$valid}">
<label class="control-label" for="campo">Modelo</label>
<input ng-model="data.campo" name="campo" type="text" class="form-control" id="campo" required>
<span ng-class="{'glyphicon glyphicon-remove form-control-feedback':datos.campo.$invalid && !datos.campo.$pristine, 'glyphicon glyphicon-ok form-control-feedback':datos.campo.$valid}"></span>
<span ng-show="datos.campo.$invalid && !datos.campo.$pristine" class="col-md-8 center badge badge-danger">Incorrecto</span>
</div>
Con Angular JS es mas facil validar campos, Checa este link
This code will check EVERY input field.
$(#loginButton).click(function() {
if (!$.trim($("input").val()) { //check ALL input fields, see if they have valid (non-falsy) values
alert("some input needs fixin'!");
} else {
submit(); //since you mentioned this in your post
$.ajax({});//or make an ajax call, or put it inside of a function and call that, the possibilities are endless..
}
});
Although this can be done in several ways, using your example, I can see that you are already returning false on validation failure. Return true from the end of your validateInput() method.
function validateInput(item) {
var div=item.closest("div");
if(item.val()==null || item.val()=="") {
div.addClass("has-error");
return false;
} else {
div.removeClass("has-error");
div.addClass("has-success");
return true;
}
}
Then, in the click event handler, check the returned value and call the form.submit()
$('#loginButton').click(function() {
var isValid = true;
$('.form-control').each(function(){
isValid &= validateInput($(this));
});
if (isValid)
{
var data = $('#loginForm').serialize();
$.ajax({
url: 'your endpoint',
type: 'POST',
data: data
});
}
});
to submit the form.
Here's a working Plunkr.
You could use this plugin. This is the best and easiest to use plugin I have found for validating a form.

Angular UI-Validate without input field (validate expression)

Im using ui-validate utils
https://github.com/angular-ui/ui-validate
The problem is to validate expression on the form without input field.
For example? I have an object
$scope.item = { field1 : 0, field2: 0, field3: 0 };
I would like to receive the error, provided expression: field1 + field2 + field3 == 0
It is common validation for the whole form. Not for some input.
You can write a small function like this (not really sure, you need to use ui-validate for this):
$scope.validate = function () {
var sum = 0;
// Sum every non Angular key
angular.forEach($scope.items, function (value, key) {
// You can also add another check below "angular.isNumber(value)" if you have some text fields
if (key.charAt(0) !== '$') {
// Call "parseInt()" method here if values are in string
sum += value;
}
});
return sum !== 0;
}
Now, display it at somewhere in your form:
<form>
<div ng-show="!validate()">There is some error. Sum can't be zero</div>
<!-- Your fields below -->
</form>
ui-validate can only be used within input tags as there is a requirement for ng-model. ng-show binding to a function would work.
Here is an example:
http://codepen.io/ctwoodwa/pen/eJmyYg
angular.module('ngExample', ['ngMessages'])
.controller('elemController', Controller1);
function Controller1() {
vm = this;
vm.item = { field1 : 0, field2: 0, field3: 0 };
vm.validate = validate
function validate() {
// Determine if the form is valid.
return (vm.item.field1 + vm.item.field2 + vm.item.field3 == 0);
};
}
<div ng-app='ngExample' ng-controller="elemController as vm">
<form name="exampleForm">
<label for="field1">Field1</label>
<input type="number" name="field1" ng-model="vm.item.field1"/>
<label for="field2">Field 2</label>
<input type="number" name="field2" ng-model="vm.item.field2"/>
<label for="field3">Field 3</label>
<input type="number" name="field3" ng-model="vm.item.field3"/>
<div ng-show="vm.validate()">
<div class="error">This form is not valid</div>
</div>
<button>Submit</button>
</form>
</div>

Categories

Resources