如何在检查输入值的同时过滤数组?

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
}