I have multiple methods which validates and return Boolean value a control. what can be best way to write the logic so that it validates and highlights all invalid controls, doesn't submit form to server and in future I have to make least code change if new control is added.
Aprroach 1. And , OR logic operator will not give correct result
if ( (Method1(ctrl1) && Method2(ctrl2) && Method3(ctrl3)))
{ // not submit to server }
else //submit the form
Approach 2 - still change in logic will require if new control is
added for validation
var valid1 = Method1(ctrl1);
var valid2 = Method1(ctrl2);
var valid3 = Method1(ctrl3);
if(va1id1 && va1id2 && va1id3)
// not submit to server
else
// submit to server
Have an array called valid which contains the result of all validations.
var valid = [];
valid.push(Method1(ctrl1));
...
var entry = valid.reduce(function(validity,state){
return validity && state; //if any entry in the valid array is false the result will be false
},true);
if(entry){
//do something
}
else{
//do something else
}
If a new validation check has to be added you have to add one line to the code though: valid.push(Method1(ctrln));
The object oriented answer: have one class / object per "check". They all go into a list of some sort. The final checking works by iterating that list to call the same method there.
That only requires you to add a new class / object for each new check you need.
Related
I have an advanced search form in a custom CMS. I need to check to make sure that the user doesn't try to submit the form without at least one field populated. No problem; this is a very stripped-down version:
var noText = false;
if(!$('#advancedId').val() && !$('#advancedTitle').val() &&
$('#advancedCoupon').val() && !$('#advancedDesc').val() ) {
noText = true;
}
if(noText) {
alert("You haven't provided any search terms. Please fill in/select at least one field.");
noText = false;
return false;
}
But we have that one QA guy who just has to really do his job, and deliberately tries searches that there's no way our client would ever do. He submitted a bug indicating that if he entered a space in every field, it passes and tries to submit.
So I tried trimming the values like this:
if(!$('#advancedId').val().trim() && !$('#advancedTitle').val().trim() &&
$('#advancedCoupon').val().trim() && !$('#advancedDesc').val().trim() ) {
noText = true;
}
This of course works if I actually enter a space in all of the fields, but throws a "Cannot read property 'trim' of null" error if I try to submit it with a space in one field, and nothing in the others.
Yes, I could do something like this:
if($('#advancedId').val()) {
$('#advancedId').val($('#advancedId').val().trim());
}
Yes, I could make it somewhat shorter with a terniary, but I'd still have to do that for over a dozen fields. Is there a better way to do this?
I would probably select them all and then do a filter. Though to make it less tightly coupled, I'd probably put a class on them and select with that instead of all the ids.
//select all the fields concerned and filter on them for non-blank values
var nonBlankFields = $('#advancedId, #advancedTitle, #advancedCoupon, #advancedDesc').filter(function(){
//default to an empty string if for some reason the value doesn't exist
return ( this.value || '' ).trim().length > 0
});
if (!nonBlankFields.length) {
alert("You haven't provided any search terms. Please fill in/select at least one field.");
return false;
}
So, i have this code but something doesn't seem to work as expected.
function validateForm() {
var x = document.forms["reg"]["username","password","first_name","last_name","age","mail"].value;
if (x==null || x=="" || x==0) {
alert("All fields must be filled out");
return false;
}
}
I get an alert if I leave any of the fields empty. Except for the last one. If I fill in every field except for mail, I can proceed. And if I only fill in mail, I can proceed as well.
How come it checks all the fields except the last one?
Or might there be an easier way to check if the fields are filled in? (I'm actually using PHP but somehow the if(empty($_POST['username']) thing doesn't work anymore, so I figured to just use JS, since it looks better with the alert message anyway.
You need to break your function up a little bit - put the field names into an array and loop through them one by one. And as stated in the comments, the null check isn't required.
function validateForm()
{
var fields = ["username", "password", "first_name", "last_name", "age", "mail"];
for(var i = 0; i < fields.length; i++)
{
var fieldName = fields[i];
var x = document.forms["reg"][fieldName].value;
if (x == "" || x == 0) {
alert("All fields must be filled out");
return false;
}
}
}
You should also do the same validation in your PHP code, as someone could easily disable JavaScript and so the data wouldn't get validated at all.
You cannot get the whole thing in an array! Instead you need to do it differently. It takes only the mail one as that's the last one in the list. So, you can do something like this:
x = [];
x.push(document.forms["reg"]["username"].value);
x.push(document.forms["reg"]["password"].value);
x.push(document.forms["reg"]["first_name"].value);
x.push(document.forms["reg"]["last_name"].value);
x.push(document.forms["reg"]["age"].value);
x.push(document.forms["reg"]["mail"].value);
And that you have built that array, you need to check for "" and 0 values in them. You need to write a function like in_array() of PHP to JavaScript to check for empty and 0 values.
Instead of all these hassles, you can happily use a jQuery form validator plugin, and it does the work well.
Is there any way of using javascript/jquery to prevent a user entering the same number twice in an input box? The user can enter as many numbers as they want (one at a time), but I need to alert the user/take other action if they try to enter the same number a second time. I have tried creating an array:
function history() {
var numbers = [];
numbers.push(document.getElementById('inputBox').value);
}
and then running:
var n = document.getElementById('inputBox').value;
if ($.inArray(n, numbers)> -1) {
// alert, do something
}
but the new array ('numbers') never gets populated by the user input, so the if clause never fires.
Something like this, perhaps? I assume you are using jQuery because of the $.inArray in your code.
var numbers = [];
$('#inputBox').change(function () {
if ($.inArray($(this).val(), numbers)) {
// Alert the user/take other action
} else {
// Otherwise, add it to the array of numbers
numbers.push($(this).val());
}
});
It would be better if there was a button the user had to click to add the new number. Otherwise, it will be quite annoying.
It looks like your numbers variable is scoped to the history() function, so the numbers variable instanced that is being set is only accessibly by the history() function. This code will accomplish what you're trying to do without a global numbers variable and prevents any duplicate numbers from being entered by intercepting and canceling the key event.
$("#inputBox").on("keydown", function(e) {
var numbers = $(this).val();
var c = String.fromCharCode(e.keyCode);
return ~numbers.indexOf(c);
});
EDIT:
Ok so I'm updating this question, to show what I've built as I've still not been able to fix this issue. Here is an image of what I've got. So as you can see,
When the user enters a value, the calculation (they are just percentage and total calculations are done "onkeyup". As you can see because of this they return "NaN". Is there a way for me to stop the field displaying a NaN and then subsequently only showing the total values?
I have thought about this and I could just get all the fields to calculate as soon as something is input into the final field? What do you think. Apologies to all those that had perviously answered my question, I am still trying to figure out the best approach, I'm just not as good with JavaScript as I am with HTML/CSS!!
You should try writing a checkNumber function that takes the entered value as its argument (rather than referring directly to each field inside the function). Something like this:
var checkNumber = function (testval) {
if ( isNaN(testval) ) {
alert('Bad!');
// clean up field? highlight in red? etc.
} else {
// call your calculation function
}
}
Then bind that function to the keyup event of each form field. There are a number of ways to do this. Look into addEventListener(), or the binding features of a framework like jQuery (.delegate() or .keyup(), e.g.).
Note that if you do bind the function to the event, you won't have to explicitly pass in the value argument. You should be able to work with a field's value within the function via this.value. So you'd have something like this:
var checkNumber = function () {
if ( isNaN( this.value ) ) {
alert('Bad!');
// clean up field? highlight in red? etc.
} else {
// call your calculation function
}
}
And then (with a naive binding approach by ID):
document.getElementById('id_of_a_field').addEventListener('keyup', checkNumber, true);
Can't you just initialize the text box with a default value, say 0?
Why don't you use 3 different functions or an argument to identify which of the inputs the user is pressing? If each of the inputs calls checkNumber(1), checkNumber(2) and checkNumber(3) you can only validate the input that the user is using instead of validating all 3 at the same time.
Alternatively you can use input validation and instead of an alert just return false to prevent the user from inputing invalid chars
How about use short-circuit evaluation with jsFiddle example
EDIT for parseFloat:
function checkNumber()
{
var sInput = parseFloat(document.getElementById('sInput').value || 0);
var dInput = parseFloat(document.getElementById('dInput').value || 0);
var pInput = parseFloat(document.getElementById('pInput').value || 0);
if (isNaN(sInput) || isNaN(dInput) || isNaN(pInput)) {
alert("You entered an invalid character. Please press 'Reset' and enter a number.");
}
}
So if pInput is undefined just use 0, but if the input has value then use that value.
SIDE NOTE: white space is actually a number, +' '; // 0
I have a form which has 4 columns and the user can dynamically add or delete rows.
Now I tried to validate this through javascript following code:-
<script type="text/javascript">
function chkempty()
{
var x=document.forms["main"]["qty[]"].value
var y=document.forms["main"]["price[]"].value
var z=document.forms["main"]["item[]"].value
if (x==null || x=="") {
alert("Quantity must be filled out");
return false;
}
if (y==null || y=="") {
alert("Price must be filled out");
return false;
}
if (z==null || z=="") {
alert("Itemcode cannot be empty");
return false;
}
}
It works for the first row but when the user selects more than one row, even after filling up values, he is getting the validation error message. can someone help me with this please?
Thanks and keep smiling.
VERY simple solution here:
Use Jquery Inline Validator
When you add new lines of content to the table, simply ensure that you have the proper class defined (such as class="validate[required,custom[email]]" ) to ensure that it will validate the field correctly as you wish. I often just do the required element, but the example I gave above also does email format checking. There are additional built in checkers for phone numbers, currency, etc.
If the user messes up an input, it will display a visually appealing tooltip like dialog next to the field with the error.
Done. Simple. Clean. Fast.
None of these solutions make up for the fact that you really need to sanitize on the server-side as well. Any Javascript can be bypassed, so it's not 100% guaranteed to be safe or accurate. But it is a good start and provides quality, instant feedback to the user.
var x=document.forms["main"]["qty[]"].value
You should loop over the elements and validate each value, instead of trying to get a value from an array, I guess.
var x=document.forms["main"]["qty"];
for ( var i=0, len=x.length; i<len; ++i ){
// validate the value of the current element.
}
EDIT: added a small example.
document.forms.form_id.control_name will return either an HTMLElementNode or a NodeList depending if there are one or many matching elements.
You can do something like:
var x=document.forms["main"]["qty[]"]
if (x.nodeName) {
// Is a Node. Work with its value
} else {
// Is a NodeList, loop over it with for
for (var i = 0; i < x.length; i++) {
var node = x[i];
// Work with its value
}
}