Javascript filtering with multiple parameters - javascript

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;
}

Related

JS operator on document.getElementById gives unexpected result

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))

Add two variables in javascript efficiently

Is there an efficient way to add two variables a and b when they could be dynamic? I also need to check if their types are numbers. I think the way I have described below is not the best/modern way to implement this. Please help.
EDIT
I also want to make sure if one the variable is not a number(or null) then the variable C gets its value from the variable which is the number . How can I do it?
const a;
const b;
let c;
// variables a and b are dynamic and could be null.
if(typeOf(a)==='number' && typeOf(b)==='number'){
if(!a && b){
c=b
}
if(a && !b){
c=a
}
if(a && b){
c=a+b
}
}
You can simply check with typeof and use the logical or operator to convert NaN to 0.
if(typeof a ==='number' && typeof b === 'number'){
c = (a || 0) + (b || 0);
}
To also allow invalid values to be treated as 0, you can use this:
c = (typeof a === 'number' ? (a || 0) : 0) + (typeof b === 'number' ? (b || 0) : 0)
It could also be written like so:
c = (typeof a === 'number' && !isNaN(a) ? a : 0) + (typeof b === 'number' && !isNaN(b) ? b : 0)
I think you're looking for
const c = (typeof a == 'number' ? a : 0)
+ (typeof b == 'number' ? b : 0);

Create loop for url parameter combinations

This might be a bit of a long shot but here we go. I've got 6 different variables that I need to create different url parameters. So for example:
var A
var B
var C
var D
var E
var F
Now I need to basically account for all options between those 6. So for example for var A I'd neeed something like:
if (A != '' && B == '' && C == '' && D == '' && E == '' && F == '') {
url += A ;
}
else if (A != '' && B != '' && C == '' && D == '' && E == '' && F == '') {
url += A + "+" + B;
}
else if (A != '' && B != '' && C != '' && D == '' && E == '' && F == '') {
url += A + "+" + B + "+" + C;
}
And so on. So basically I'd need to go through all the combinations like the above example, which I'm currently doing manually and which works fine, but there must be a better way of doing this?
You could filter the items, after taking them into an array and join with +.
result = [a, b, c, d, e, f].filter(Boolean).join('+');

How i can create simple condition for query mysql?

i have complex for handle request filtering . and i have
var p = payment , o = outlet, and m = member
and i need different condition for every single var.. like
p == 'all' && m =='all' && o =='all'
p == 'all' && m == 'all' && o != 'all'
p == 'all' && m != 'all' && o == 'all'
p == 'all' && m != 'all' && o != 'all'
p != 'all' && m == 'all' && o == 'all'
p != 'all' && m == 'all' && o != 'all'
p != 'all' && m != 'all' && o != 'all'
p != 'all' && m != 'all' && o == 'all'
because i want query for different condition , example
if(p == 'all' && m =='all' && o =='all'){
"select a,b,c,d from table"
}
if(p == 'all' && m == 'all' && o != 'all'){
"select a,b,c,d from table where o=o"
}
can i create simple way ? because i think this is so ugly
Here's one way:
var params = {
p: 'all',
m: '2',
o: '7'
};
var conds = Object.keys(params)
.map(key => ({ name: key, value: params[key], isAll: params[key] == 'all' }))
.filter(c => !c.isAll)
.map(c => `\`${c.name}\` = '${c.value}'`)
.join(" AND ");
var query = "SELECT FROM table" + (conds ? " WHERE " + conds : "");
console.log(query);
Start with a parameter object, turn it into an array of objects containing the key and value, plus the all test.
filter out alls
map to query part
join
Try to change your logic. I'm assuming most of the code will remain the same, so you can do something like this:
var query = 'something'
if (p = 'all') {
query = query + ' ... '
}
if (m = 'all') {
query = query + ' ... '
}
if (o = 'all') {
query = query + ' ... '
}
ps. It's not a good idea to set the actual query in javascript, due to sql injection, database column exposure etc. You best do this server side.

Why is the 'o' is true? Javascript(Angular)

Help me please, I'm trying to make a rule for the little game and there is the problem.
I'm creating winning combination and say if the cell && cell+1 && cell+2 == to 'X' then you win, but when between two "X"s presents "o" it also says that "X" wins. Why? Please see my code and the game example on link a the bottom.
this.rezult = function(){
this.arr2.forEach(function(arr, i, innerArr){
arr.forEach(function(val, j){
var wincomb = innerArr[i][j] && innerArr[i][j+1] && innerArr[i][j+2];
var wincomb2 = innerArr[i][j] && innerArr[i+1][j] && innerArr[i+2][j];
var wincomb3 = innerArr[i][j] && innerArr[i+1][j+1] && innerArr[i+2][j+2];
console.log(wincomb == "X" && innerArr[i][j] !== "o");
// console.log(innerArr);
// THE RULE
if(wincomb == "X"){
alert(' X wins!');
}
});
});
};
Link to JSFiddle
In JavaScript, the && operator has interesting behavior with non-boolean values.
If the left-side of && is "truthy", the result is the right-side.
If the left-side of && is "falsey", the result is the left-side.
All non-empty strings are "truthy".
So, consider these examples:
("A" && "B" && "C") === "C"
("" && "B" && "C") === ""
(0 && "B" && "C") === 0
("X" && "X" && "O") === "O"
("O" && "O" && "X") === "X"
By the looks of it, you're trying to check if all 3 values are equal. You shouldn't use && for that, you should use === for that.
At the risk of doing your homework for you ;) here's a good way to do this:
function areTheSame(a,b,c) {
return a === b && b === c;
}
var down = areTheSame(innerArr[i][j], innerArr[i][j+1], innerArr[i][j+2]);
var across = areTheSame(innerArr[i][j], innerArr[i+1][j], innerArr[i+2][j]);
var diagonal = areTheSame(innerArr[i][j], innerArr[i+1][j+1], innerArr[i+2][j+2]);
if (down || across || diagonal) {
var winner = innerArr[i][j];
alert( winner + " wins!");
}

Categories

Resources