Dosage values are not passing correct through validation - javascript

I'm coding a function to validate if a number is a valid dosage. A valid dosage is given by value from 0 to 100 (inclusive range). It looks simple, but there are 3 conditions:
The value is not required, so empty value should return true;
There can exist one optional '%' percent sign at the end;
Decimal places are also optional.
I think I am close to the final function, but there are one test where my function fails, and I don't understand why:
function checkDosage(originalValue) {
var validDosage, isNumeric,
value = originalValue;
isNumeric = function(num) {
return !isNaN(num);
}
// take off percent sign if exists
if (value.slice(-1) == '%') {
value = value.slice(0, -1);
}
// get numeric value
value = parseFloat(value);
// check if it is really a number
isNumeric = isNumeric(value);
// conditional for dosage
validDosage = value >= 0 && value <= 100;
// treatment
if (!originalValue || isNumeric && validDosage) {
return true; // valid
}
return false; // invalid
}
checkDosage(''); // true
checkDosage('0'); // true
checkDosage('%'); // true
checkDosage('-1%'); // false
checkDosage('10.5%'); // true
checkDosage('10%%'); // true ??????? THIS SHOULD BE FALSE
checkDosage('100%'); // true
checkDosage('101%'); // false
Thanks for your time.

The problem is using parseFloat, which discards any trailing characters it finds.
Instead, use Number(string) which will either return you a number or the value NaN (not a number). Then your isNumeric function can be replaced by a call to the built in function isNaN

You're merely checking if the string ends with a %. You aren't checking that there is exactly zero or one %s.
In your percent sign logic, you could do something like this:
if (value.slice(-1) === '%') {
value = value.slice(0, -1);
if (value.slice(-1) === '%') {
return false;
}
}
This will chop off the percent sign. If there's still a percent sign at the end of the string, then that means there was more than one %. So this fails your validation, return false.
EDIT: The reason your existing logic doesn't catch the double % is because if the string was 10%%, and you chopped off the last %, then it'd be 10%. If you call parseFloat('10%'), you'll get back 10, which passes your isNumeric test.

Related

JavaScript - Check if input is a number

I'm facing the following (basic) problem: I want to check if an input from an HTML-input field is not greater than 5 or not a number. If this is given the function should return true. Otherwise (so if greater than 5 or a number) it should resturn false. The validation if the number is not greater than 5 works fine so far but when I add the typeof-argument this one doesn't works.
This is my code so far, thanks in advance!
function isValidStart(start) {
if (start.trim().length > 5 || typeof(start) === 'number') {
return false
}
return true
An Element.value (input, select, textarea etc) will always be a String.
Test if a single-digit integer range is used can be achieved with a small Regex and RegExp.prototype.test().
Test an integer of length 5
const isValidStart = v => /^\d{1,5}$/.test(v); // or use [0-5]
console.log(isValidStart("1")) // true
console.log(isValidStart("55555")) // true
console.log(isValidStart(2)) // true
console.log(isValidStart("a12")) // false
You don't even have to care if a value is a String or Number.
Single integer:
to match single digits from range 1 to 5:
const isValidStart = v => /^[1-5]$/.test(v); // or use [0-5]
console.log(isValidStart("1")) // true
console.log(isValidStart(2)) // true
console.log(isValidStart("a")) // false
console.log(isValidStart("6")) // false
You can use the Number.isFinite() function to check if a variable is a finite number, which in your use case should do the Job.
let intVar = 2;
Number.isFinite(intVar);
$true
However it looks like your start variable is not actually a number as you can't call .trim() on a number. So this if statement will never return True.
You should typecast your variable. https://www.w3schools.com/js/js_type_conversion.asp
let reg = new RegExp(/^\d{0,5}$/);
console.log(reg.test('1'));
console.log(reg.test('12'));
console.log(reg.test('123'));
console.log(reg.test('1234'));
console.log(reg.test('12345'));
console.log(reg.test('string'));
console.log(reg.test('124var123'));

Finding variable types from a string

Pardon if this question has already been answered however I'm struggling to find the any answers to it.
I'm looking to see if I can convert variable types to a string in the code below.
input = prompt('Type something please', 'your input here')
alert(input + ' is a ' + typeof input)
i.e. if the user were to type 1 typeof would return number, or if the user were to enter true it would return a boolean
You can run the input through a series of parseInt, parseFloat and
parseBool
functions.
Whenever you get a valid result, return it.
Something similar to:
if (parseInt(input) != NaN) {
return "int"
}
if (parseFloat(input) != NaN) {
return "float"
}
Generally, all inputs per your example will return a string careless of what they entered or intended to enter. We could however build a few logics to check if what they entered is; Strings (Alphabets only) or an integer (numbers only) or any other ones per a few other logics you could base your checks on.
One of the quickest ways to check if an input contains a number or not;
isNaN(input) // this returns true if the variable does NOT contain a valid number
eg.
isNaN(123) // false
isNaN('123') // false
isNaN('1e10000') // false (This translates to Infinity, which is a number)
isNaN('foo') // true
isNaN('10px') // true
you could try regex (which is not always ideal but works)
var input = "123";
if(num.match(/^-{0,1}\d+$/)){
//return true if positive or negative
}else if(num.match(/^\d+\.\d+$/)){
//return true if float
}else{
// return false neither worked
}
You could also use the (typeof input) but this will be more convenient if your user is going to enter an expected set of entries
var input = true;
alert(typeof input);
// This eg will return bolean
Let me know if this helps.

Use of arguments causing function to always return false

I would like to sum the args of my function if and only if the two args are numbers (hence my first function).
function checkNum() {
var num = 0;
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] !== 'number') {
return false;
}
}
return true;
}
function addTogether() {
var num = 100;
if ( checkNum() ) {
return arguments[0] + arguments[1];
} else {
return undefined;
}
}
addTogether(2, "");
However my second function performs the sum no matter what the args values are. Any hints on how to fix this ?
checkNum() isn't declared to explicitly take any arguments (which implies to anyone looking at the function that none are expected) and you are not sending any when you call it, so arguments.length is always 0, you never enter into your loop body and you always return true.
Your second function is called by passing two arguments, so your references to arguments[0] and arguments[1] are valid there. But, even still, the use of arguments isn't really meant for all argument passing.
It's best to set up your functions with named parameters and then you can access them via those names. The use of arguments (while valid), is not encouraged as the default mechanism for accessing arguments. It's generally used for validation (ensure that the correct amount of parameters were passed to the function before the function attempts to operate on them, for example).
Also, it's best to test for numbers with a regular expression because typeof can "lie" to you. For example:
// Would you ever think that not a number is of type "number"?!
console.log(typeof NaN === "number");
Now, depending on your criteria for "number", there are two ways you could go.
Only numeric digits are allowed (i.e. 6 is allowed, "6" is not)
// It's better for this function to test one number
// at a time, so you can react to that particular
// success or failure
function checkNum(num) {
// No loop and no if/then needed, just return
// whether the argument is a number, but don't
// test for typeof number because typeof NaN === "number"
// Use a regular expression instead
var reg = /[0-9]+$/; // digits or strings of characters that are from 0 - 9
// Test for only digits not numbers passed as strings
// For example 6 is good, "6" is bad. Here, the use of "typeof"
// is safe because you are also testing that the input is digits
// or characters from 0 to 9 (NaN wouldn't pass this test)
return reg.test(num) && typeof num === "number"; // true or false will be returned
}
function addTogether(val1, val2) {
// Test each input, independantly so that you can react more granularly
if ( checkNum(val1) && checkNum(val2) ) {
return val1 + val2;
}
// It's not necessary to have an "else" that returns undefined because
// that's what will happen as long as you don't return anything else.
}
console.log(addTogether(2, "")); // undefined
console.log(addTogether(2, 6)); // 8
console.log(addTogether(2, "6")); // undefined because "6" is a string, not a digit
Numeric digits and numeric characters are allowed (i.e. 6 and "6" are allowed). In this case, you'd need to ensure that numeric characters get converted to numbers before addition is done so you get mathematical addition and not string concatenation.
// It's better for this function to test one number
// at a time, so you can react to that particular
// success or failure
function checkNum(num) {
// No loop and no if/then needed, just return
// whether the argument is a number, but don't
// test for typeof number because typeof NaN === "number"
// Use a regular expression instead
var reg = /[0-9]+$/; // digits or strings that are from 0 - 9
// Test for only digits and numbers passed as strings
return reg.test(num); // true or false will be returned
}
function addTogether(val1, val2) {
if ( checkNum(val1) && checkNum(val2) ) {
// If checkNum returns true for numeric characters as well as digits, then
// you'd need to ensure that the characters get converted to numbers so that
// you get mathmatical addition and not string concatenation. That would be done like this:
return +val1 + +val2
}
// It's not necessary to have an "else" that returns undefined because
// that's what will happen as long as you don't return anything else.
}
console.log(addTogether(2, "")); // undefined
console.log(addTogether(2, 6)); // 8
console.log(addTogether(2, "6")); // 8 because "6" is converted to 6, not a string of "6"
The arguments array, as evaluated within checkNum, contains the arguments passed to checkNum. But you aren't passing any arguments to checkNum. Try changing the if statement to
if ( checkNum(arguments[0], arguments[1]) )
You aren't passing any arguments to checkNum. You can fix this with apply:
// ...
if (checkNum.apply(this, arguments)) {
// ...
Edit: That would allow you to check any number of arguments passed to addTogether. If you only want to allow for two arguments, you can used named parameters:
function checkNum(a, b) {
return typeof a === 'number' && typeof b === 'number';
}
function addTogether(a, b) {
if (checkNum(a, b)) return a + b;
else return undefined; // line not needed
}
addTogether(2, "");

Issue with using isNaN()

Actually this is a simple program to check weather the number is divisible by 2 or not divisible by 2 or input given is not a number. According to my information isNaN('berry) should give me true as'berry' is a string but in my code this goes quite wrong.
The code is :
var isNum = function(number) {
// My code goes here!
if (number%2===0){
return true
}
else if (isNaN(number)){
console.log("enter the number not the string");
return number
}
else{
return false
}
};
isNum('berry');
The code above returns me false when I run it. Any help will be appreciated.
This is the screenshot
You can try using parseInt() or parseFloat() to convert variables to their integer or float equivalent before use elsewhere.
You can try using typeof to determine the variable type.
var isNum = function(number) {
var number_parsed = parseFloat( number );
if (isNaN(number) || typeof number == 'string' ){
console.log("enter the number not the string");
return number
} elseif(number_parsed % 2 ===0){
return true
} else{
return false
}
};
isNum('berry');
Your code gives the following output (run it here) and it's correctly working
var isNum = function(number) {
// My code goes here!
if (number%2===0){
return true
}
else if (isNaN(number)){
console.log("enter the number not the string");
return number
}
else{
return false
}
};
isNum('berry');
isNan() returns true when the argument is actually NaN. You provided 'berry', not NaN and so isNan() returns false.
Quoting the documentation:
The isNaN() function determines whether a value is NaN or not.
.
Return value
true if the given value is NaN; otherwise, false.

isFinite of space giving true value

I am trying to validate a price field. I was trying this:
var productId = document.getElementById("productId");
var productName = document.getElementById("productName");
var productPrice = document.getElementById("price");
alert(isFinite(productPrice.value));
if(isNaN(productPrice.value)||!isFinite(productPrice.value)){
error = document.getElementById("priceError");
error.innerHTML = "Please enter correct value";
productPrice.style.border="thin solid red";
}else{
error = document.getElementById("priceError");
error.innerHTML = "";
}
The line alert is giving me true when the input is space/ multiple spaces only.
This is my HTML page.
<td>Price</td>
<td><input type = "text" id = "price" size = "14"/></td>
Thanks
Why this happens i cant say, but this code should solve the problem
isFinite(parseFloat(" ")) // false
// because -->
parseFloat(" "); // => result NaN
// tested in Chrome 27+ on Win7
in the MDN refernce of isNaN here
it says
isNaN(" "); // false: a string with spaces is converted to 0 which is not NaN
Update:
in the Reference of isFinite found Here it states that isFinite only returns false if the argument is:
NaN
positive infinity, (Number.POSITIVE_INFINITY)
negative infinity (Number.NEGATIVE_INFINITY)
In any other Case it returns true. (like Paul S mentioned)
Now i Think i got all loose ends, and in that course learned something. :)
with window.isFinite, you must be aware of the issues that window.isNaN suffers from when coercing types.
window.IsNaN Summary
Determines whether a value is NaN or not. Be careful, this function is
broken. You may be interested in ECMAScript 6 Number.isNaN.
Examples
isNaN(NaN); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN(true); // false
isNaN(null); // false
isNaN(37); // false
// strings
isNaN("37"); // false: "37" is converted to the number 37 which is not NaN
isNaN("37.37"); // false: "37.37" is converted to the number 37.37 which is not NaN
isNaN(""); // false: the empty string is converted to 0 which is not NaN
isNaN(" "); // false: a string with spaces is converted to 0 which is not NaN
// This is a false positive and the reason why isNaN is not entirely reliable
isNaN("blabla") // true: "blabla" is converted to a number. Parsing this as a number fails and returns NaN
In ECMAScript 6 there are new methods Number.isNaN and Number.isFinite that address these issues. (of course these are not available in many browsers)
Number.isFinite is equivalent to
function isFinite(number) {
return typeof number === "number" && window.isFinite(number);
}
So as a solution, you would need to consider something like this (cross-browser).
Note: this solution will still allow you to enter hexadecimal or scientific notations, "0xA", "1e10"
Javascript
function isFinite(number) {
return typeof number === "number" && window.isFinite(number);
}
function trim(string) {
return string.replace(/^\s+|\s+$/g, "");
}
var price = document.getElementById("price");
price.onchange = function (e) {
var evt = e || window.event,
target = evt.target || evt.srcElement,
value = trim(target.value) || "NaN",
number = +value;
console.log("number:", number);
console.log("isFinite:", isFinite(number));
}
On jsfiddle
You could do it using reqular expression.
Try this.
function validatePrice() {
var el = document.getElementById('price');
if (
el.value.length < 14 &&
/^ *\+?\d+ *$/.test( el.value )
)
{
return true;
}
return false;
}
This function checks if the input is positive integer. I didnt know if you want floated values also.
If you do, switch the regex to this /^ *+?\d+((.|,)\d+)? *$/

Categories

Resources