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.ingredientsis 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
}
