I have 2 arrays bodyparts
& equipment
.
Array objects have been put into dropdown menus.
I am trying to filter
results based on object values
eg. If i select 'chest' from bodyparts array
and 'barbell' from equipment array
i only want results with a matching values from 'chest' and 'barbell' to appear in the console
.
This is what the array object looks like
{bodyPart: 'neck', equipment: 'body weight', id: '1403', name: 'neck side stretch', …}
const dataDiv = document.getElementById("data")
const apiURL = 'https://exercisedb.p.rapidapi.com/exercises/bodyPart/{chest}'
let mainList = []
let bodypartsList = []
let equipmentList = []
async function getApiURL(endpoint, value) {
console.log(`https://exercisedb.p.rapidapi.com/exercises/${endpoint}/${value}`);
const response = await fetch(`https://exercisedb.p.rapidapi.com/exercises/${endpoint}/${value}`, {
"method": "GET",
"headers": {
"x-rapidapi-host": "exercisedb.p.rapidapi.com",
"x-rapidapi-key": "myApiKey"
}
})
const data = await response.json();
if (endpoint == "bodypart") {
bodypartsList = data
} else {
equipmentList = data
}
mergeLists()
}
function mergeLists() {
mainList = bodypartsList.concat(equipmentList);
displayData(mainList)
}
//bodypart code
const bodyparts = ["Body Parts", "back", "cardio", "chest", "lower arms", "lower legs", "neck", "shoulders", "upper arms", "upper legs", "waist"]
const equipment = ["Equipment", "assisted", "band", "barbell", "body weight", "cable", "dumbbell", "ez barbell", "hammer", "kettlebell", "leverage machine", "medicine ball", "resistance band", "roller", "rope", "smith machine", "tire", "trap bar", "weighted"]
const exercises = document.getElementById("exercises");
window.addEventListener("load", function () {
createDropdown("bodypart", bodyparts);
})
window.addEventListener("load", function () {
createDropdown("equipment", equipment);
})
// const select = document.createElement("select"); //---create the select element
// const option = document.createElement("option"); //---create options for select
function createDropdown(name, items) {
const select = document.createElement("select"); //---create the select element
select.className = "selectMenu"
select.name = name
select.id = name
for (let i = 0; i < items.length; i ) { //---as long as 'i' is less than the number of items increase by 1
const item = items[i]; //---declaring 'i' as items
const option = document.createElement("option"); //---create options for select
option.setAttribute("value", item); //---places item value into options
option.innerHTML = item; //---change content of options to items
select.appendChild(option); //---append options to select
}
exercises.appendChild(select); //---append data to options
select.addEventListener("change", function () {
const item = select.value;
dataDiv.innerHTML = ''; //<------Clears previous results from page
// console.log(item);
getApiURL(name, item);
})
}
function displayData(data) {
// console.log(data);
let d1 = document.getElementById("equipment")
let d2 = document.getElementById("bodypart")
console.log(d2.value);
if (d2.value && d1.value !== -1 ){
const result = data.filter(word => {
return (word.name.indexOf(d1.value))
});
console.log(result);
result.forEach(element => {
const div = document.createElement("div");
const p = document.createElement("p");
// const img = document.createElement("img");
// img.className = "appGifs"
p.innerHTML = element.name
// img.src = element.gifUrl
div.appendChild(p)
// div.appendChild(img)
div.className = "card"
dataDiv.appendChild(div)
});
}
}
HTML
<div class="row-md-6 offset-md-2">
<div class="col-sm-10" style="border:1px solid blue">
Logo goes here
<div class="row">
<div class="col-8 col-sm-6" style="border:1px solid red">
<div id="exercises" class="bg-primary align-items-center"></div> <!--Dropdown Buttons-->
</div>
<div class="col-4 col-sm-6" style="border:1px solid red">
<div id="data"></div> <!--Result Data-->
</div>
</div>
</div>
</div>
<div id="appSubmit"></div> <!--Submit button-->
It is currently showing all merged results, i think it is adding filtered results to the mainList
array
and not removing unwanted results.
I really cannot find what i have done wrong and appreciate any help
Thanks
CodePudding user response:
You are mixing strings and indexes. I'm also assuming you don't want to filter with 0 index like the other posted answer does.
let result = data;
if (d1.selectedIndex > 0) {
const selected = d1.value;
result = result.filter(({equipment}) => equipment.includes(selected));
}
if (d2.selectedIndex > 0) {
const selected = d2.value;
result = result.filter(({bodyPart}) => bodyPart.includes(selected));
}
CodePudding user response:
So what I have understood from If I select 'chest' from bodyparts array and 'barbell' from equipment array I only want results with matching values from 'chest' and 'barbell' to appear in the console.
this line is, If you select chest from dropdown, you want to show all the data whose name matches with the selected value.
You are doing like this:
const result = data.filter(word => {
return (word.name.indexOf(d1.value))
});
indexOf() method returns the position of the first occurrence of a specified value in a string. indexOf() method returns -1 if the value is not found.
It will never return you the result that you are expecting. So instead of doing that, You can try something like this:
const result = data.filter(word => word.name.includes(d2.value));
this will return all the values that match with the selected value of D2 dropdown. For d1, you need to do the same.
Update
change your display function with this
function displayData(data) {
debugger;
// console.log(data);
let d1 = document.getElementById("equipment");
let d2 = document.getElementById("bodypart");
console.log(d2.value);
let value1;
let value2;
//get filtered value for d2
if (d2.value){
value2 = data.filter(word => word.name.includes(d2.value));
}
////get filtered value for d1
if (d1.value){
value1 = data.filter(word => word.name.includes(d1.value));
}
//merge both the value into one using spread operator(... this is called spread operator in JS)
let result = [
...value1,
...value2
];
//loop over the final result
if(result.length > 0){
console.log(result);
debugger;
result.forEach(element => {
debugger;
const div = document.createElement("div");
const p = document.createElement("p");
// const img = document.createElement("img");
// img.className = "appGifs"
p.innerHTML = element.name
// img.src = element.gifUrl
div.appendChild(p)
// div.appendChild(img)
div.className = "card"
dataDiv.appendChild(div)
});
}
}
CodePudding user response:
I think the problem is in the if condition within your function displayData
if (d2.value && d1.value !== -1 ){
const result = data.filter(word => {
return (word.name.indexOf(d1.value))
});
If there is no match between d1.value
and word.name
, the condition returns -1, not 0, which means even if there is no match, it also returns true (-1 means true, only 0 means false).
So you could simply change this condition to
return word.name.indexOf(d1.value) !== -1
CodePudding user response:
in js not-primitives like arrays and objects are Pass by reference, so whenever you want to compare two arrays,you have to change the data types. you have to change objects and array to string, then do the compare. use JSON.stringify for doing that. the code below is just a sample:
const arr1 = []
const arr2 = []
console.log(arr1 === arr2) //false
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)) //true