JS operator on document.getElementById gives unexpected result - javascript

I am using this JS code without any issues:
if(document.getElementById('add_calc_srt_gew').value.length != '' &&
document.getElementById('add_calc_dia_inner').value.length != '' &&
document.getElementById('add_calc_dia_out').value.length != '' &&
document.getElementById('add_breedte').value.length != '') {
// do something }
I need to add one more check. When add_calc_dia_out is larger then add_calc_dia_inner
So I have changed the JS to:
if(document.getElementById('add_calc_srt_gew').value.length != '' &&
document.getElementById('add_calc_dia_inner').value.length != '' &&
document.getElementById('add_calc_dia_out').value.length != '' &&
document.getElementById('add_breedte').value.length != '' &&
(document.getElementById('add_calc_dia_out').value > document.getElementById('add_calc_dia_inner').value)) {
// do something }
But the code that should be triggered is not triggered. Also no errors are shown. What is the correct way to be sure that add_calc_dia_out is larger then add_calc_dia_inner ?

Here is a DRY version
const num = str => isNaN(str) || str.trim() === "" ? 0 : +str;
const srt_gew = num(document.getElementById('add_calc_srt_gew').value),
dia_inner = num(document.getElementById('add_calc_dia_inner').value),
dia_out = num(document.getElementById('add_calc_dia_out').value),
breedte = num(document.getElementById('add_breedte').value);
if (srt_gew && dia_inner && dia_out && breedte && dia_out > dia_inner) { /* do something */ }

You are compare 2 number in string. It will cause unexpected behavior like '9' > '11'. You have to parseInt() them first. Try this:
... && parseInt(document.getElementById('add_calc_dia_out').value) > parseInt(document.getElementById('add_calc_dia_inner').value)) {
Also, you should check if it's a valid number or not before doing the compare:
!Number.isNaN(document.getElementById('add_calc_dia_out').value) && !Number.isNaN(document.getElementById('add_calc_dia_inner').value))

Related

Javascript filtering with multiple parameters

I need to filter my content with multiple parameters that I am taking from fields. The fields could also be empty, so I need to get all the values that are not empty. And filter by those.
What is the best way to achieve this without making a lot of if and else if conditions like this:
if (a !== '' && b !== '' && c !== '' && d !== '' && e !== ''){
// none is empty, filter by a & b & c & d & e
}
else if ( b !== '' && c !== '' && d !== '' && e !== ''){
// a is empty, filter by b & c & d & e
}
else if ( a !== '' && c !== '' && d !== '' && e !== ''){
// b is empty, filter by a & c & d & e
}
else if ( b !== '' && a !== '' && d !== '' && e !== ''){
}
else if ( b !== '' && c !== '' && a !== '' && e !== ''){
}
else if ( b !== '' && c !== '' && d !== '' && a !== ''){
}
else if ( c !== '' && d !== '' && e !== ''){
}
else if ( b !== '' && d !== '' && e !== ''){
}
else if ( b !== '' && c !== '' && e !== ''){
}
else if ( b !== '' && c !== '' && d !== ''){
}
else if ( a !== '' && d !== '' && e !== ''){
}
and so on...
Alternatively, how can I get all the unique possible combination of these 5 letters?
Edit ::
The actual code would look something like this
//a/b/c take value of dropdown items, that match with data on an object
if (a != '' && b != '' && c != '') {
for (const i in ParticipationList.TaskMetadata) {
if (ParticipationList.TaskMetadata[i].attendance == a && ParticipationList.TaskMetadata[i].monitoring_status == b && ParticipationList.TaskMetadata[i].monitoring_status == c) {
filteredaudience[i] = { ['id']: i }
}
console.log(filteredaudience)
// get all the items that match with the object properties
}
}
So if a or b or c is empty, I can't still make the same call, as it would not match anything on the object.
The logic:
Since javascript has short-circuit evaluation, we'll just use a bunch of conditions in the format:
field === "" || (condition to filter using field)
Because of said "short-circuiting", the right side part will only be reached if the field is not empty (i.e. if the left side is false because field !== ""). However, if the field is empty then field === "" will be true and the right side part won't be reached and the whole condition will yield true resulting in the filtering for this field to be skipped.
Multiple conditions should be joined together by the logical && operator and each one of those conditions should be wrapped in parenthesis () because the operator && is higher in precedence than the || operator.
If the data to filter is an array:
For arrays, just use the conditions as the value returned from the callback of filter like so:
let filteredData = data.filter(item =>
(a === "" || (condition for field 'a' against 'item'))
&&
(b === "" || (condition for field 'b' against 'item'))
&&
(c === "" || (condition for field 'c' against 'item'))
&&
(d === "" || (condition for field 'd' against 'item'))
&&
(e === "" || (condition for field 'e' against 'item'))
);
If the data to filter is an object:
In case the data is an object and you can't use filter like above, you can still use the same logic, you just have to use the conditions inside if like so:
let filteredaudience = {};
for (const i in ParticipationList.TaskMetadata) {
if ((a === "" || ParticipationList.TaskMetadata[i].attendance === a)
&& (b === "" || ParticipationList.TaskMetadata[i].monitoring_status === b)
&& (c === "" || ParticipationList.TaskMetadata[i].monitoring_status === c)
&& (d === "" || ParticipationList.TaskMetadata[i].?????????? === d)
&& (e === "" || ParticipationList.TaskMetadata[i].?????????? === e)) {
filteredaudience[i] = { id: i };
}
}
Depending on how the actual filtering process works, it might be possible to incrementally filter your result instead of doing it simultaneously.
For example, if your data is an array, you might write:
let data = ...;
if (a != '') {
data = data.filter(elem => checkForA(a, elem));
}
if (b != '') {
data = data.filter(elem => checkForB(b, elem));
}
...
Maybe you can also incrementally augment the filter object itself and THEN apply the built filter.
Please enter more details ...
For now, what I understood was that you want to get all the
values that are not empty.
for this:
let allElements = [a, b, c, d, e]
let notEmpty = []
allElements.forEach(element => {
if (element !== '')
notEmpty.push(element)
});
console.log(notEmpty)
A common mistake for new developers is to create long, complicated and repetative if statements with tons of && and || symbols or long strings of if/else if
Instead of this, write a simple search predicate. This is a function which takes some parameters, and reduces them to either true or false.
Within said function, run each filter one at a time. As soon as one fails, return false.
var data = [
{ colour : "red", weight : 2, name : "Example 1"},
{ colour : "orange", weight : 15, name : "Example 2"},
{ colour : "yellow", weight : 10, name : "Test 1"},
{ colour : "green", weight : 24, name : "Test 2"}
];
console.log(search(data, "red", [], ""));
console.log(search(data, "", [5,20], ""));
console.log(search(data, "", [], "Test"));
function search(data, colour, weights, name) {
return data.filter(row=>testRow(colour, weights, name, row));
}
// much easier to read.
function testRow(colourFilter, weightFilter, nameSearchFilter, row) {
// run each filter one at a time. If any fail, "short circuit" out.
if (colourFilter != "" && row.colour == colourFilter) {
return false;
}
// sometimes, a double if statemnt is easier to read.
if (weightFilter.length > 0) {
if (row.weight < weightFilter[0] || row.weight > weightFilter[1]) {
return false;
}
}
// sometimes, the actual rule is a bit complex.
if (nameSearchFilter != "") {
if (row.name.indexOf(nameSearchFilter) < 0) {
return false;
}
}
// we survived all filters.
return true;
}

Improving if-else with multiple values?

Is there a better way to do this?
if(cpf.length !== 11 || cpf === "00000000000" || cpf === "11111111111" ||
cpf === "22222222222" || cpf === "33333333333" || cpf === "44444444444" ||
cpf === "55555555555" || cpf === "66666666666" || cpf === "77777777777" ||
cpf === "88888888888" || cpf === "99999999999"){
You could debate if this is better but this is what I like to do in that sort of situation:
// Name this something relevant to the problem
var possibleValues = ["0000000000", ...];
if (possibleValues.includes(cpf)) {
// do stuff
}
or if you're in an environment that doesn't have includes
if (possibleValues.indexOf(cpf) > -1) {
// do stuff
}
Another possibility is using a regular expression:
if (cpf.length === 11 && cpf.match(/^(\d)\1+$/)) {
// do stuff
}
^: Start at the beginning
(\d): Look for a digit and remember it
\1+: Look for the remembered digit repeatedly
$: Hit the end of the string
Using indexOf Something like
var possibleValues = [ "00000000000", "1111111111" ]; //add more values
if ( cpf.length != 11 || possibleValues.indexOf( cpf ) != -1 )
{
//value matching
}
Alternative Ecmascript5 solution using isNaN() and RegExp.text() functions:
if (cpf.length !== 11 || (!isNaN(f = cpf[0]) && new RegExp("^"+ f + "{11}$").test(cpf))) {
// do something
}
isNaN() - to check if we have only numbers(at start)
new RegExp("^"+ f + "{11}$").test(cpf) - to test if we have a sequence of same 11 digits

Validate CreditCard Number and checked radio button javascript

I have radio buttons radioVisa, and radioMaster. If either one is checked, I need to first check to see which one is selected and then validate that the card number entered is valid. I also need to make sure that only numbers are entered.... I am not allowed to use any regular expression techniques.... If the radioVisa is checked, it seems to work but when I added the code for the radioMaster, if it is checked it does't work.... Can someone tell me what I am doing wrong please....
function isValidCardNumber(num, isVisa, isMaster){
var card = new Array();
if (document.getElementById('radioVisa').checked){
card = isVisa;
}
if (num[0] != '4' || num.length != 16 ){
return false;
} else {
return true;
} else if (document.getElementById('radioMaster').checked){
card = isMaster;
}
if (num[0] != '51' || num[0] != '52' || num[0] != '53' ||
num[0] != '54' || num[0] != '55' || num.length != 16 ){
return false;
} else {
return true;
}
if (num[0] != '51' || num[0] != '52' || num[0] != '53' ||
num[0] != '54' || num[0] != '55' || num.length != 16 )
You can not combine all those numbers.You need to specify individually.
or
var numbers= ["51", "52", "53", "54",55];
var index = numbers.indexOf(num[0]);
It will return -1 if that is not exist otherwise return the index

Input only with correct numeric

i wanted to ask how i can combine my regex with the if( ( !regex.test( sybol.... condition, if there is a possibility, and also, how I can shorten my code? without loosing good code view. Also, dash can be only in first place and only one in input, and the same with dot.
$( this ).bind( 'keypress', function( e ){
var code = e.keyCode || e.which;
var symbol = String.fromCharCode( code );
var regex = /[-0-9]|[\b]/;
var currVal = $( this ).val();
var insideInput = currVal.indexOf( '-' );
if( ( !regex.test( symbol ) && code != 37 && code != 39 && code != 46 ) ||
( code == 45 && insideInput == 0 ) || ( currVal.length != 0 && code == 45 ) ) {
e.preventDefault();
}
});
If you want digits only input, you can use following:
$('#test').on('input', function() {
var oldVal = $(this).val();
// remove everything but digits
var newVal = oldVal.replace(/[^\d]/g, '');
// put leading minus back in place (if there was one)
if(oldVal.trim().length > 0 && oldVal.trim()[0] == '-') {
newVal = '-' + newVal;
}
$(this).val(newVal);
});​
See this DEMO.
If you want more, please update your question (describe what are you trying to achieve with your script).
So i combined Michal Klouda ideas and mines and done this function:
$('input').bind('keypress paste', function(e) {
var currVal = $(this).val();
var code = e.keyCode || e.which;
var symbol = String.fromCharCode( code );
var regex = /[0-9\-]|[\b]/;
if(
!regex.test( symbol ) && code != 37 && code != 39 && code != 46 ||
symbol == '%' ||
currVal.length > 0 && currVal[0] == '-' && symbol == '-' ||
currVal.length > 0 && symbol == '.' && currVal.indexOf( '.' ) > -1 ||
currVal.length < 1 && symbol == '.' ||
currVal.length < 2 && symbol == '.' && currVal[0] == '-'
){
e.preventDefault();
}
});
Some explanations:
regex = /[0-9\-]|[\b]/;
Removes all non numeric, exept dash, %, backspace symbols.
Why it isn't removing % symbol, i can't find. ( one more place to inprove code )
code != 37 // leaves left arrow
code != 39 // leaves right arrow
code != 46 // allows to delete code with delete button
symbol == % // prevents from percentage symbol
Other conditions allow you to write one dot and one dash symbol.
Dash allowed only in first place, dot allowed in two conditions: with dash or without.
With dash allowed from 3 position, without from 2 position, but only once. Also it prevents user to paste the code from clipboard.
CODE TESTED:
IE7+
FF
Chrome
Safari
Opera
Try DEMO
P.S: thanks Michal Klouda for help.

how to fix jslint The '&&' subexpression should be wrapped in parens error

I put everything in parentheses but code below still throws error in jslint:
Problem at line 5 character 104: The '&&' subexpression should be wrapped in parens.
if ((typeof (c1) === 'string') && (typeof (c2) === 'string') && (c1 !== n...
How to fix ?
"use strict";
function t() {
var c1, c2;
if (((typeof (c1)) === 'string') && ((typeof (c2)) === 'string') && (c1 !== null) && (c2 !== null) && ((c1.trim()) === '') || ((c2.trim()) !== '')) {
return;
}
}
It's complaining about the form if(a && b && c || d) because (I suppose) it's not immediately obvious whether && or || will take precedence. Fix it to look like if(a && b && (c || d)) and it will stop complaining.
I think it wants this:
if (((typeof (c1) === 'string') && (typeof (c2) === 'string') && (c1 !== null) && (c2 !== null)) && ((c1.trim()) === '') || ((c2.trim()) !== '')) {
wrap the 4 anded expressions on the left of the && at 100.
I'm fairly certain you want the following:
function t() {
var c1, c2;
if (typeof c1 === 'string' && typeof c2 === 'string' && c1 !== null && c2 !== null && (c1.trim() === '' || c2.trim() !== '')) {
return;
}
}
Not everyone knows the precedence for boolean logic, so they want you to wrap the c1.trim() || c2.trim() statements in parenthesis so it's clear how they get operated.
As a side note, I think it's ridiculous that jslint wants spaces between my operators and my operands. I think it's much more clear when there is NOT a space.

Categories

Resources