Home > Blockchain >  How to filter an array an array while checking the value of an input?
How to filter an array an array while checking the value of an input?

Time:04-19

I'm having an issue while trying to filter my array (see below), i'm trying to filter my recipes while checking if an ingredient is inside a recipe.

You'll find a minimalist example of my problem below. First the JSON

{"recipes": [
    {
        "id": 1,
        "name" : "Limonade de Coco",
        "servings" : 1,
        "ingredients": [
            {
                "ingredient" : "Lait de coco",
                "quantity" : 400,
                "unit" : "ml"
            },
            {
                "ingredient" : "Jus de citron",
                "quantity" : 2
            },
            {
                "ingredient" : "Crème de coco",
                "quantity" : 2,
                "unit" : "cuillères à soupe"
            },
            {
                "ingredient" : "Sucre",
                "quantity" : 30,
                "unit" : "grammes"
            },
            {
                "ingredient": "Glaçons"
            }
        ]
    }]
}
    <input  />

    <script>
        const input = document.querySelector(".input")
        async function getRecipes() {
            const response = await (await fetch("./recipes.json")).json();
            const recipes = response.recipes;
            return ({ recipes: [...recipes] });
        };

        function filter(recipes) {
            input.addEventListener("input", () => {
                var filteredRecipes = recipes.filter(recipe => {
                    return recipe.ingredients.ingredient.toLowerCase().includes(input.value.toLowerCase())
                })
                console.log(filteredRecipes)
            })
        }

        async function init() {
            const { recipes } = await getRecipes();
            filter(recipes)
        }

        init()
    </script>

This error is coming to the console :

index.html:23 Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase')

which is completely fine since each ingredient isn't an ingredient. I tried a forEach on the ingredient's array but i couldn't get the result.

So, filteredRecipes should return here, or my recipe, or an empty array.

Thanks in advance

CodePudding user response:

  • Since recipe.ingredients is an array, you have to use .filter() or its equivalent to check if an ingredient includes the searched text.

Change your filter function to something like this

function filter(recipes) {
    input.addEventListener("input", () => {
        var filteredRecipes = recipes.filter(recipe => {
            return recipe.ingredients.filter(({ingredient}) => ingredient.toLowerCase().includes(input.value.toLowerCase())).length > 0
        })
        console.log(filteredRecipes)
    })
}

CodePudding user response:

This is probably caused by the "await" in front of the fetch in the init function. Try it like so;

async function init() {
        const { recipes } = getRecipes().then(res => filter(res.recipes))
        .catch(err => //catch any error
        );
}

CodePudding user response:

You're binding an event listener on the input every time you filter.

You only need to set it once at startup.

Also to provide a more verbose alternative:

function filter_recipes(recipes, value) {
   let ans = []
   let filter = value.toLowerCase()
   
   for (let recipe of recipes) {
     for (let item of recipe.ingredients) {
        if (item.ingredient.toLowerCase().includes(filter)) {
          ans.push(recipe)
        }
     }
   }
   
   return ans
}
  • Related