Would someone be able to take a look at my code and see what I'm missing here?
I have a multi-page form with quite a lot of inputs, and I would like to keep "next page" buttons and the final "submit" buttons disabled until all the fields are full.
I am trying to recreate the process on a smaller scale but in my tests, I cannot seem to re-enable the disabled submit input. I've checked the console and the JS is logging the variable elements so I'm not sure what I'm missing.
function checkForm()
{
var elements = document.forms[0].elements;
var cansubmit= true;
for(var i = 0; i < elements.length; i++)
{
if(elements[i].value.length == 0 || elements[i].value.length == "" || elements[i].value.length == null)
{
cansubmit = false;
}
document.getElementById("myButton").disabled = !cansubmit;
}
};
<form>
<label for="firstName">First Name:</label> <input type="text" id="firstName" onkeyup="checkForm()" />
<br />
<label for="lastName">Last Name:</label> <input type="text" id="lastName" onkeyup="checkForm()" />
<button type="button" id="myButton" disabled="disabled">Test me</button>
</form>
Your elements array includes your button, which has no value. This will cause your loop to always evaluate to cansubmit = false;.
Try this instead: https://jsfiddle.net/e00sorLu/2/
function checkForm()
{
var elements = document.forms[0].elements;
var cansubmit= true;
for(var i = 0; i < elements.length; i++)
{
if(elements[i].value.length == 0 && elements[i].type != "button")
{
cansubmit = false;
}
}
document.getElementById("myButton").disabled = !cansubmit;
};
Answer was already accepted, but here are a few other things you might consider:
The way you have it set up now, for absolutely anything other than an empty string "" you're setting button.disabled = false and enabling the button.
You're checking value.length 3 times, but you actually want to
check .value instead. The length property is only a numeric
value for how many code units are in the string - it won't ever be
"" or null, so the only thing you're really checking is the very
first condition for an empty string of length 0.
You're also not accounting for multiple white spaces in a blank string, so " " would be valid) ... or
special characters, so this would be valid: (function goodByeWorld(evil){//do the bad things})();
You're running the checkForm() function on all form elements
(including the <button>) after every single keystroke. This is unnecessary.
Aside from including <button>, which was pointed out in the accepted answer & will always cause this to fail, you should either validate each individual form element with inline error checking
(preferable), or validate all of them once just prior to submission (preferable to server-side validation & kicking it back after submission).
You could bind to onblur() instead and send the current element's value as an argument once that field loses focus. e.g. change to: function checkValue(value) {//validate the value}) and either onblur = checkValue(this) in the HTML or preferably a non-inline event handler that lives in the JS file instead.
You could still do it onkeyup = checkValue(this) to check after every keystroke, but change the function to only check 1 element instead of checking t.h.e. e.n.t.i.r.e. f.o.r.m. dozens of times.
This approach would let you individually keep track of each separate form element's validity (lots of options here depending on what "valid" means - store an array of values, objects with values or "valid/invalid" flags, etc, switch on the field labels to validate this for different types of information). You can run additional validation on the individual elements as well (e.g. min/max name length, eliminating special characters, etc), and display real-time error checking messages next to each form element.
You're defaulting to cansubmit = true which doesn't make much sense, given what you intend for this code to do. Using !cansubmit only serves to confuse yourself & others reading the code. For readability, consider inverting it to disableSubmit so it's in sync with the button.disabled state, which should only be true or false.
Or you can use jQuery.
<script type="text/javascript">
function checkForm() {
var cansubmit = false;
$('form input[type="text"]').each(function (index, element) {
if (element.value == "") {
cansubmit = true;
}
});
document.getElementById("myButton").disabled = cansubmit;
}
</script>
Related
My function, addthisTxt, is not checking the length. It should not exceed 11. Below is what I have tried so far; I'd like to keep on adding text until it reaches the max length, otherwise it should restrict the user from adding more.
HTML
<input type="checkbox" name="chkbxr" value="add this offer on wrapper"
(change)="addthisTxt($event.target.getAttribute('txt'), $event.target.checked)">
JavaScript
addthisTxt(txt, checked): void {
if (checked) {
if((this.v.offerName.length +txt.length) >= 55){
this.v.offerName = this.v.offerName + txt;
}
this.v.offerName = this.v.offerName;
}
}
You are setting the value on this.v.offerName. The UI element is not bound to this JavaScript variable and you need to set the value of the UI input element to restrict the value.
Hello guys need some help here. i want to have limit the numbers inputted in my input field by putting max attribute to it. i have no problem with that until i use my keyboard to input data on it. seems like the max attribute is not filtering the input coming from the keyboard.
e.g
<input type="number" max="5" />
i can't go until 6 using the up and down arrow but when i manually put 6 using keyboard it's accepts it. how can i prevent? thank you
You would need to use JavaScript to do it. This will not let the user enter a number higher than 5:
<input type="number" max="5" onkeyup="if(this.value > 5) this.value = null;">
Another possible solution is to completely block the keyboard input by replacing onkeyup=".." event in the code above with onkeydown="return false".
have no problem with that until i use my keyboard to input data on it.
seems like the max attribute is not filtering the input coming from
the keyboard
This is how HTML5 validation/constraint work. However, it will invalidate when the form submits. Alternatively, you can validate it yourself. To validate yourself, you need to wire up Javascript and call the checkValidity() on the input element.
checkValidity() of the constraints API will check the validity state of the element and will return the state of whether the input element validate or not. This will also set the validity object on the input so that you can query more details.
Ref: https://html.spec.whatwg.org/multipage/forms.html#constraints and https://html.spec.whatwg.org/multipage/forms.html#form-submission-algorithm
You can also use the :invalid selector in CSS to highlight invalid inputs.
Example Snippet:
var input = document.getElementById('test'),
result = document.getElementById('result');
input.addEventListener('blur', validate);
function validate(e) {
var isValid = e.target.checkValidity();
result.textContent = 'isValid = ' + isValid;
if (! isValid) {
console.log(e.target.validity);
}
}
input[type=number]:invalid {
border: 2px solid red;
outline: none;
}
<label>Enter value and press tab: </label><br/>
<input id="test" type="number" min="1" max="10" />
<hr/>
<p id="result"></p>
You can use javascript to restrict the maximum input value to 5.
HTML
using oninput as a event handler
<input type="number" max="5" oninput="checkLength(this)" />
JS
function checkLength(elem) {
// checking if iput value is more than 5
if (elem.value > 5) {
alert('Max value is 5')
elem.value = ''; // emptying the input box
}
}
DEMO
An Utility Function to Solve Two Problem
Problem 1: Limit user input to maximum n digit
For this use n number of 9 as max parameter. As an example if you want to limit user input in 4 digit then max param value will be 9999.
Problem 2: Limit user input at a maximum value
This is intuitive. As an example If you want restrict the user input to maximum 100 then max param value will be 100.
function getMaxInteger(value, max) {
if(!value) return;
if( parseInt(value) <= max ) {
return value;
}
return getMaxInteger(value?.substr(0, value?.length-1), max);
}
function maxInt(value, max) {
return getMaxInteger(value?.replace(/\D/,''), max);
}
Use this maxInt method on input change handler
ngModelChange for Angular
onChange for React
v-on:change or watch for Vue
onkeyup="if(this.value > <?=$remaining?>) this.value = null; else if(this.value < 1) this.value = null;"
I have a form with inputs which also has an iFrame embedded in the form which also has inputs (pseudo HTML):
<input type="text" name="one" value="one" />
<input type="text" name="two" value="two" />
<input type="text" name="three" value="three" />
<iframe
<input type="text" name="bacon" value="bacon">
</iframe>
<input type="text" name="four" value="four" />
<input type="text" name="five" value="five" />
When the user presses tab they are taken from input to input even inside the iframe fields selecting bacon after three. We all love bacon.
I also have some javascript that attempts to focus the next input on enter key:
$(document).ready(function() {
$(document).on('keydown', 'input', function(ev) {
// Move to next on enter
if (ev.which === 13) {
var inputs = $(':tabbable');
var next = inputs.index(this) + 1;
var input = inputs.eq(next == inputs.length ? 0 : next);
input.focus();
return false;
}
});
});
The problem is the javascript enter key code never focuses the bacon field, it will skip right over it. jsfiddle:
https://jsfiddle.net/54n8mqkh/4/
Let's all skip answers that include not using the iFrame. I know it is not an ideal implementation. However, I would accept ANY answer that allows the enter key to move through all the fields consistently including the iframe using any type of javascript. It does not have to be jquery specific.
I have tried a few different approaches to solve this but none I have found works. Thanks in advance to anyone who has a solution.
You need to focus inside of the iframe like so :
var frameBody = $("#IFrame_input").contents().find("input");
frameBody.focus();
I am going to answer my own question - after a few more hours I was able to solve my use case by expanding my selector to include the iframe. Then I build the array of inputs manually and while iterating I checked the node type for an iframe. If / when I encountered an iframe, I did the same select inside the iframe and added the inputs within the iframe:
$(document).ready(function() {
// Parent level helper function
window.tabToNext = function(me) {
var selector = ':tabbable, iframe';
var inputElems = [];
$(selector).each(function(index) {
var nodeName = $(this).prop('nodeName').toLowerCase();
if (nodeName == 'iframe') {
$(this).contents().find(selector).each(function(index) {
inputElems.push(this);
});
} else {
inputElems.push(this);
}
});
var inputs = $(inputElems);
var next = inputs.index(me) + 1;
if (next == inputs.length) next = 0;
var input = inputs.eq(next);
input.focus();
return false;
}
$(document).on('keydown', 'input', function(ev) {
// Move to next on enter
if (ev.which === 13) {
return window.tabToNext(this);
}
});
// Focus the first input
$('input[name=one]').focus();
});
FWIW: I could not just expand the selector as best I could tell and also I tried to use $.add to build the collection starting with an empty jQuery collection:
var foo = $([]);
foo.add(someElement);
... but it does not honor the order you add. It will re-order to the DOM according to the docs which SEEMS like it should be right, but for some reason my iframe child fields always ended up last and messed up the tab order.
Anyhow, I hope if someone else has this issue some day you find this helpful. Working solution:
https://jsfiddle.net/wbs1zajs/6/
What I'm going after is a code that will gather all my text input fields and detect whether or not they have any input. If so I'd like for there to be a glow effect added, if they're left empty or they delete the data and leave it empty I'd like for the glow effect to turn off.
So far from everything I've found this is what I came up with so far, it doesn't work of course, but it's the best I could try to rationalize.
function glow(){
var text = document.getElementsByClassName('tex_inp01 tex_inp02');
if (text.value ==null){
text.style.boxShadow="#8fd7d2 0px 0px 22px";
}
else
remove.style.boxShadow;
}/**function**/
I used the .getElementsByClassName because the getElementsById didn't support multiple IDs as it seems, but if there's another more efficient way of gathering them all please share.
Simple solution can be adding class having glow with javascript:
var text = document.getElementsByClassName('tex_inp01 tex_inp02');
text[0].className = text[0].className + " glow";
DEMO
Note: If you want to add glow class to each input then you have to iterate through loop and add class to each element. Because text is
HTMLCollection of elements.
You need to get the value of each element, not of the HTMLCollection returned by document.getElementsByClassName; Array.prototype.forEach can help with this. Then, a value can’t be null, but empty.
Edit: Wait a minute… you want the glow effect if the element has an input, right? Then your if-else statement is the wrong way around.
This is the correct function:
function glow() {
"use strict";
Array.prototype.slice.call(document.getElementsByClassName("tex_inp01 tex_inp02")).forEach(function(a) {
if (a.value !== "") {
a.style.boxShadow = "0px 0px 22px #8fd7d2";
}
else {
a.style.boxShadow = "";
}
});
}
You have a couple of mistakes in your existing code (as presented in the question): (1) text.value ==null - do not check against null, because an inputs value will never be a null. Check its length. (2) remove.style.boxShadow; - I think that was a typo. It should have been text.style.boxShadow = 'none'.
..to be a glow effect added, if they're left empty or they delete the
data and leave it empty I'd like for the glow effect to turn off..
You can check if the input has been left empty by simply checking the length of the value. However, to check if the input has been entered and then deleted you will have to keep a flag to keep track of that. You can do that by hooking up the change event on inputs and then setting a flag via data attribute. Later when you are checking each input for applying a style, along with the length also check this attribute to see if the input was edited out.
Here is a simple example putting together all of the above (explanation in code comments):
var inputs = document.getElementsByClassName("a b"), // returns a collection of nodelist
button = document.getElementById("btn"); // just for the demo
button.addEventListener("click", checkInputs); // handle click event on button
[].forEach.call(inputs, function(elem) { // iterate over all selected inputs
elem.addEventListener("change", function() { // handle change event
this.setAttribute("data-dirty", true); // set a data attribute to track..
}); // .. a flag when it is changed
});
function checkInputs() {
[].forEach.call(inputs, function(elem) { // iterate over selected inputs
var isDirty = elem.getAttribute("data-dirty"); // check the dirty flag we set
if ((elem.value.length > 0) || (isDirty)) { // if empty or changed
elem.style.boxShadow = "none"; // reset the style
} else {
elem.style.boxShadow = "#f00 0px 0px 5px"; // else apply shadow
}
});
}
<input class="a b" /><br /><br /><input class="a b" /><br /><br />
<input class="a b" /><br /><br /><input class="a b" /><br /><br />
<button id="btn">Check</button>
If you wanted to validate the inputs while the user is typing, you can use keyboard events to check the value of the input(s):
document.querySelector('input[type="text"]').addEventListener('keyup',
function(event){
var element = event.target;
if (element.value.trim() === '') {
element.classList.add('empty');
} else {
element.classList.remove('empty');
}
});
See fiddle for example: http://jsfiddle.net/LrpddL0q/.
Otherwise this could be implemented the same way without the addEventListener to perform as a one-off function.
Jquery can help you as the following
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
$(document).ready(function () {
$(".MyInput").bind('keypress', function () {
$('.MyInput').css("boxShadow", "#8fd7d2 0px 0px 22px");
});
$(".MyInput").bind('keydown', function () {
if ($(".MyInput").val() == "") {
$('.MyInput').css("boxShadow", "none");
}
});
});
</script>
HTML:
<input type="text" value="" class="MyInput" />
this code working only online If you need to download Jquery library visit this
https://jquery.com/download/
I'm making a form that requires at least one field to be filled AND all inputs have to be either integers or decimals. I'm using jquery's validation plugin to validate. I've reworked something I found here that seems to partially do the trick. right now I have:
<SCRIPT>
jQuery.validator.addMethod("require_from_group", function(value, element, options) {
var numberRequired = options[0];
var selector = options[1];
var validOrNot = $(selector, element.form).filter(function() {
// Each field is kept if it has a value
return $(this).val();
// Set to true if there are enough, else to false
}).length >= numberRequired;
if(!$(element).data('being_validated')) {
var fields = $(selector, element.form);
fields.data('being_validated', true);
fields.valid();
fields.data('being_validated', false);
}
return validOrNot;
// {0} below is the 0th item in the options field
}, jQuery.format("Please fill out at least {0} of these fields."));
$(document).ready(function(){
var container = $('#errorContainer');
$("#FORMMM").validate( {
rules: {
groceries: {digits: true,require_from_group: [1,".at_least_one"]},
gas: {digits: true,require_from_group: [1,".at_least_one"]},
hotels: {digits: true,require_from_group: [1,".at_least_one"]}
},
success: function(label) {
label.html(" ").addClass("checked");
},
errorContainer: container,
errorLabelContainer: $("ol", container),
wrapper: 'li',
meta: "validate"
});
});
</SCRIPT>
the HTML is below, in my actual form there are 15 input fields, I'm just condensing it for here:
<form action="results.php" target="_blank" id="FORMMM">
<div style="clear:both">
<label for="groceries">Groceries</label>
<div style="float:right">
$<input name="groceries" type="text" class="at_least_one idleField"></div>
</div>
<div style="clear:both">
<label for="gas">Gas</label>
<div style="float:right">
$<input name="gas" type="text" class="at_least_one idleField">
</div>
</div>
<div style="clear:both">
<label for="hotels">Hotels</label>
<div style="float:right">
$<input name="hotels" type="text" class="at_least_one idleField">
</div>
</div>
<div id="button">
<input name="" type="submit" value="Calculate" class="calc_button" style="cursor:hand">
</div>
</form>
<div id="errorContainer">
<h4>errors</h4>
<ol>
</ol>
</div>
Right now there are two problems with the validation. If all fields are left blank, I get 3 error messages when I only need one!
Also, if I enter a letter into one of the inputs, I get the "digits only" error message for a second, but the form still submits anyways, since the 2nd test of having at least 1 field be filled makes up for not having digits.
Am I doing this in a totally wrong way? None of the examples I can find here or on the jquery forums seem to fit exactly. What direction should I go to solve this?
It seems I found a solution. See comments in code. Live demo.
jQuery.validator.addMethod(
"require_from_group", function(value, element, options) {
var numberRequired = options[0];
var selector = options[1];
var fields = $(selector, element.form);
var filled_fields = fields.filter(function() {
// it's more clear to compare with empty string
return $(this).val() != "";
});
var empty_fields = fields.not(filled_fields);
// we will mark only first empty field as invalid
if (filled_fields.length < numberRequired && empty_fields[0] == element) {
return false;
}
return true;
// {0} below is the 0th item in the options field
}, jQuery.format("Please fill out at least {0} of these fields."));
$(document).ready(function(){
var container = $('#errorContainer');
$("#FORMMM").validate( {
// We must to force validation of entire form because
// when we remove value from 2-nd field
// the 1-st field becomes invalid.
onfocusout: function() { $("#FORMMM").valid() },
onkeyup: function() { $("#FORMMM").valid() },
rules: {
// note: you can use variable to avoid repeating
// of the same code
groceries: {
number: true,
require_from_group: [1, ".at_least_one"]
},
gas: {
number: true,
require_from_group: [1,".at_least_one"]
},
hotels: {
number: true,
require_from_group: [1,".at_least_one"]
}
},
success: function(label) {
label.html(" ").addClass("checked");
},
errorContainer: container,
errorLabelContainer: $("ol", container),
wrapper: 'li',
meta: "validate"
});
});
You have two problems:
Failing the digits check doesn't prevent the form from submitting - you see the message, but then it submits.
If none of the three fields are present, you get the error message three times.
You can see the starting state here: http://jsfiddle.net/jclark/NR29t/1/; the only thing I changed is that the form now fires an alert when submitted instead of submitting the form.
Taking these one at a time, I'll start with #1. I noticed that the digit check will stop the form from submitting, if the non-digit entry is on the last field of the form. Otherwise, it will continue. It turns out the problem is in your require_from_group method. As it written, re-validates the whole form:
if(!$(element).data('being_validated')) {
var fields = $(selector, element.form);
fields.data('being_validated', true);
fields.valid();
fields.data('being_validated', false);
}
Reading through the post you linked, and the posts linked there, this appears to be present to cause the error message to appear as soon as the first required input loses focus, instead of only on submit. Is the a requirement for your use? Because this seems to be the cause of the first issue. The "being_validated" logic prevents a infinite chain (where element one revalidates element two, which revalidates element one, ad infinitum), but, this still means that as each field is checked, it will revalidate the all fields in the group form. It looks like this revalidation is causing the problem. I think what is happening is if the first field is non-digit, that error is noted, but when the last field is validated, it revalidates the whole form, but the skip-inifite-loop check causes the other fields to be skipped; since the last field is valid, the whole form submits.
I'm about 98% sure I've got that right. I do know, however, that removing that block eliminates the problem. See this version:
http://jsfiddle.net/jclark/NR29t/2/
Now for the second issue. The behavior of showing all errors on the field is by design, and usually makes sense - just not a group of fields are inter-related like this. Fortunately, Validator provides the groups option, to denote a group of fields that should only report the first error found. See this version:
http://jsfiddle.net/jclark/NR29t/3/
Submit with no fields filled in, and you only see one message. However, there's a new problem: the "Please enter only digits" message only shows immediately after you leave an invalid input, or when the field is focused. I think this is a Validator bug; see this Stack Overflow question: jquery validate - groups and their labels. Specifically, if input 3 is populated but not a digit, then input 1 and two are valid (the don't contain non-digits, and some other field is populated), so I think that is clearing out the error for the group.
Unfortunately, I don't fix for that issue at this time. The linked SO question above suggests a somewhat fragile workaround of writing a validation method specifically to check all fields at once, so they all fail together and the message stays. Here's a demo of that:
http://jsfiddle.net/jclark/NR29t/4/
Here's the custom validator:
jQuery.validator.addMethod("digits_for_group", function(value, element, selector) {
var validOrNot = $(selector, element.form).filter(function() {
// Each field is kept if it has a value
return $(this).val().search(/[^0-9]/) != -1;
// Set to true if there are enough, else to false
}).length == $(selector, element.form).length;
return validOrNot;
}, jQuery.format("Please enter only digits"));
It works, but I don't love it; it requires re-implementing the digits check; it you have other validation checks you'd need to do the same.
Hope this helps.