Home > Back-end >  Filter 2 arrays return based on matching inner values javascript
Filter 2 arrays return based on matching inner values javascript

Time:11-18

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
  • Related