如何在检查输入值的同时过滤数组?
How to filter an array an array while checking the value of an input?
我在尝试过滤我的数组时遇到问题(见下文),我正在尝试过滤我的食谱,同时检查食谱中是否包含某种成分。
您会在下面找到我的问题的一个极简示例。
首先是 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 class="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>
控制台出现此错误:
index.html:23 Uncaught TypeError: Cannot read properties of undefined
(reading 'toLowerCase')
这完全没问题,因为每种成分都不是一种成分。我在成分数组上尝试了 forEach,但我无法得到结果。
所以,filteredRecipes 应该 return 在这里,或者我的食谱,或者一个空数组。
提前致谢
这可能是init函数中fetch前面的“await”造成的。试一试;
async function init() {
const { recipes } = getRecipes().then(res => filter(res.recipes))
.catch(err => //catch any error
);
}
- 由于
recipe.ingredients
是一个数组,您必须使用 .filter()
或其等效项来检查成分是否包含搜索到的文本。
将你的 filter
函数改成这样
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)
})
}
您在每次过滤时都在输入上绑定了一个事件侦听器。
启动时只需设置一次即可。
同时提供更详细的替代方案:
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
}
我在尝试过滤我的数组时遇到问题(见下文),我正在尝试过滤我的食谱,同时检查食谱中是否包含某种成分。
您会在下面找到我的问题的一个极简示例。 首先是 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 class="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>
控制台出现此错误:
index.html:23 Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase')
这完全没问题,因为每种成分都不是一种成分。我在成分数组上尝试了 forEach,但我无法得到结果。
所以,filteredRecipes 应该 return 在这里,或者我的食谱,或者一个空数组。
提前致谢
这可能是init函数中fetch前面的“await”造成的。试一试;
async function init() {
const { recipes } = getRecipes().then(res => filter(res.recipes))
.catch(err => //catch any error
);
}
- 由于
recipe.ingredients
是一个数组,您必须使用.filter()
或其等效项来检查成分是否包含搜索到的文本。
将你的 filter
函数改成这样
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)
})
}
您在每次过滤时都在输入上绑定了一个事件侦听器。
启动时只需设置一次即可。
同时提供更详细的替代方案:
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
}