Javascript, сопоставьте флажки с JSON

У меня есть:

  • Количество флажков
  • Кнопка для отправки
  • Строковый объект JSON.
  • Функция для проверки того, какие флажки отмечены, и возврата их значений в предупреждении или console.info с помощью даже прослушивателя на моей кнопке отправки.
  • Выходной DIV

Как я могу сравнить значения, которые я получаю от функции, которая проверяет, какие флажки отмечены, со значениями в строковом объекте JSON и отображать их в выходном DIV? Скажем, я проверяю поля «Сыр» и «Чеснок» и ожидаю получить следующий результат:

  • Рецепт 1: Сыр, Помидор, Чеснок
  • Рецепт 2: Сыр, Картофель, Майонез, Говядина, Чеснок, Масло

HTML:

<form action = "" method = "">
    <input type = "checkbox" value = "Cheese">Cheese<br>
    <input type = "checkbox" value = "Tomato">Tomato<br>
    <input type = "checkbox" value = "Garlic">Garlic<br>
    <input type = "checkbox" value = "Bacon">Bacon<br>
    <input type = "checkbox" value = "Paprika">Paprika<br>
    <input type = "checkbox" value = "Onion">Onion<br>
    <input type = "checkbox" value = "Potato">Potato<br>
    <input type = "checkbox" value = "Mayo">Mayo<br>
    <input type = "checkbox" value = "Beef">Beef<br>
    <input type = "checkbox" value = "Garlic">Garlic<br>
    <input type = "checkbox" value = "Butter">Butter<br>

    <input type = "button" value = "Get recipes" id = "getRecipesButton">
</form>

<div id = "output">The results end up here</div>

JS:

//Recipes JSON-string:
var recipes = [
    {
        name:"recipe1",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Tomato"},
                {ingredient:"Garlic"}
            ]
    },
    {
        name:"recipe2",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Bacon"},
                {ingredient:"Paprika"},
                {ingredient:"Onion"}
            ]
    },
    {
        name:"recipe3",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Potato"},
                {ingredient:"Mayo"},
                {ingredient:"Beef"},
                {ingredient:"Garlic"},
                {ingredient:"Butter"}
            ]
    }
];
//Test to retrieve single, specific entries: 
//      console.info(recipes[1].ingredients[0].ingredient);


//Test to get/return the checked values of the checkboxes:
function selectedBoxes(form) {
    let selectedBoxesArr = [];
    let inputFields = form.getElementsByTagName('input');
    let inputFieldsNumber = inputFields.length;

    for(let i=0; i<inputFieldsNumber; i++) {
        if (
            inputFields[i].type == 'checkbox' &&
            inputFields[i].checked == true
        ) selectedBoxesArr.push(inputFields[i].value);
    }
    return selectedBoxesArr;
}

var getRecipesButton = document.getElementById('getRecipesButton');
getRecipesButton.addEventListener("click", function(){
    let selectedCheckBoxes = selectedBoxes(this.form);
    alert(selectedCheckBoxes);
});

>>Скрипка

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
1 228
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вот как вы можете установить значения на основе вашей текущей структуры. Имейте в виду, что неясно, какой рецепт вы хотели бы применить в любой момент времени, поэтому приведенный ниже код применит к форме первый рецепт.

//Recipes JSON-string:
var recipes = [{
    name: "recipe1",
    ingredients: [{
        ingredient: "Cheese"
      },
      {
        ingredient: "Tomato"
      },
      {
        ingredient: "Garlic"
      }
    ]
  },
  {
    name: "recipe2",
    ingredients: [{
        ingredient: "Cheese"
      },
      {
        ingredient: "Bacon"
      },
      {
        ingredient: "Paprika"
      },
      {
        ingredient: "Onion"
      }
    ]
  },
  {
    name: "recipe3",
    ingredients: [{
        ingredient: "Cheese"
      },
      {
        ingredient: "Potato"
      },
      {
        ingredient: "Mayo"
      },
      {
        ingredient: "Beef"
      },
      {
        ingredient: "Garlic"
      },
      {
        ingredient: "Butter"
      }
    ]
  }
];

var getRecipesButton = document.getElementById('getRecipesButton');
getRecipesButton.addEventListener("click", function() {
  for (let ingredient of recipes[0].ingredients) {
    document.querySelector(`input[value='${ingredient.ingredient}']`).setAttribute('checked', true);
  }
});
<form action = "" method = "">
  <input type = "checkbox" value = "Cheese">Cheese<br>
  <input type = "checkbox" value = "Tomato">Tomato<br>
  <input type = "checkbox" value = "Garlic">Garlic<br>
  <input type = "checkbox" value = "Bacon">Bacon<br>
  <input type = "checkbox" value = "Paprika">Paprika<br>
  <input type = "checkbox" value = "Onion">Onion<br>
  <input type = "checkbox" value = "Potato">Potato<br>
  <input type = "checkbox" value = "Mayo">Mayo<br>
  <input type = "checkbox" value = "Beef">Beef<br>
  <input type = "checkbox" value = "Garlic">Garlic<br>
  <input type = "checkbox" value = "Butter">Butter<br>

  <input type = "button" value = "Get recipes" id = "getRecipesButton">
</form>

<div id = "output">The results end up here</div>

Не стесняйтесь комментировать, если у вас есть какие-либо вопросы

Что вы думаете об этом быстром предложении, я знаю, что оно не очень элегантно:

HTML (замените этим)

<ul id = "output">The results end up here</ul>

JS

var getRecipesButton = document.getElementById('getRecipesButton');
getRecipesButton.addEventListener("click", function(){
    let selectedCheckBoxes = selectedBoxes(this.form);
    document.getElementById("output").innerHTML = "";
  var res = [];
  recipes.forEach(function(r,k){
    r['ingredients'].forEach(function(i,idx){
        if (selectedCheckBoxes.includes(i.ingredient)) {
        res.push(r);
      }
    });
  });
// remove duplicate then display the recipe with the ingredient
    res.filter(function(item, index){
      return res.indexOf(item) >= index;
    }).forEach(function(r){
      var ingredient = r.ingredients.map(function(r) { return r.ingredient}).join(", ");
      var name = r.name + " : "+ingredient ;
      var ul = document.getElementById("output");
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(name));
      ul.appendChild(li);
    });
});

Вот рабочая версия: https://jsfiddle.net/8esvh65p/

Здорово! Это абсолютно сработало. Другие ответы вернули массивы (т.е. не полное решение). Я также получаю значение других ответов и могу использовать их, если мне нужно изменить функциональность. Я также настроил кнопку отправки, чтобы она была невидимой (нулевые высота, ширина, отступы и поля), и вместо этого обернул ее в eventlistener для флажков, поэтому всякий раз, когда кто-то устанавливает или снимает флажок, он будет обновляться мгновенно.

Streching my competence 10.02.2019 14:34

Пожалуйста. Кстати, я уверен, что мы можем «оптимизировать» код, но, возможно, на потом.

mub 10.02.2019 14:40

возможно. Честно говоря, я думаю, что это довольно коротко и аккуратно. Но я буду работать с этим некоторое время, так как он будет служить моим личным поиском рецептов для покупок на основе ингредиентов, которые у меня есть под рукой, поэтому я уверен, что окажусь в ситуациях, когда я хотел бы или должен был бы обновляйте его по пути (обычно так бывает с большинством вещей).

Streching my competence 10.02.2019 14:43
Ответ принят как подходящий

Вы можете отфильтровать свой массив рецептов только для рецептов, которые включают все выбранные ингредиенты, например:

let filtered = recipes.filter((recipe) => {
    return selectedCheckBoxes.every((selected) => {
        return recipe.ingredients.some((ingredient) => {
            return ingredient['ingredient'] === selected;
        });
    });
});

Итак, для каждого из рецептов мы проверяем, содержится ли в рецепте выбранный ингредиент каждый. В таком случае:

  • фильтр(): Отфильтровывает любой рецепт, который не содержит всех выбранных ингредиентов;
  • каждый(): Проверяет, присутствует ли каждый выбранный ингредиент в текущем рецепте, оцениваемом с помощью filter();
  • немного(): Проверяет, совпадают ли некоторые из ингредиентов рецепта с текущим выбранным ингредиентом, оцениваемым функцией every().

Я отредактировал вашу скрипку, чтобы вы могли увидеть, как она работает: https://jsfiddle.net/byce6vwu/1/

Редактировать

Вы можете преобразовать возвращенный массив в html следующим образом (я также изменил выходной div на ул:

let outputRecipes = '';
  filtered.forEach((recipe) => {
    let stringIngredients = recipe.ingredients.map((val) => {
        return val.ingredient;
    }).join(',');
        outputRecipes += `<li>${recipe.name}: ${stringIngredients}</li>`;
  });
    document.getElementById('output').innerHTML = outputRecipes;

Я отредактировал скрипку: https://jsfiddle.net/ys0qofgm/

Итак, для каждого ингредиента в массиве мы преобразуем объект ингредиента: {ingredient: "Cheese"} только в строку "Сыр" и соединяем все элементы массива, используя запятую в качестве разделителя. Затем создайте элемент ли для каждого рецепта и поместите в него строку рецепта.

Спасибо! Поскольку он возвращает массивы, я не выбрал его в качестве решения, хотя в некоторой степени он абсолютно делает то, что я искал. Я проголосовал за него, так как он является полезен и кое-чему меня научил!

Streching my competence 10.02.2019 14:38

Любое предложение о том, как вывести массив и возвращаемый внутренний массив?

Streching my competence 10.02.2019 15:47

Я отредактировал ответ, как делать то, что вы хотите.

Pedro leal 10.02.2019 17:06

Здорово! Не могу отблагодарить вас достаточно. Теперь у меня есть намного лучшие инструменты, чтобы изучить, как сделать что-то подобное самому.

Streching my competence 10.02.2019 17:43

Этот код будет делать то, что вы хотите. Он перебирает каждый ингредиент, проверяя набор рецептов и их ингредиенты, чтобы проверить, включает ли этот рецепт этот ингредиент. Возвращаются только рецепты, которые включают все выбранных ингредиентов:

//Recipes JSON-string:
var recipes = [
	{
		name:"recipe1",
		ingredients:
			[
				{ingredient:"Cheese"},
				{ingredient:"Tomato"},
				{ingredient:"Garlic"}
			]
	},
	{
		name:"recipe2",
		ingredients:
			[
				{ingredient:"Cheese"},
				{ingredient:"Bacon"},
				{ingredient:"Paprika"},
				{ingredient:"Onion"}
			]
	},
	{
		name:"recipe3",
		ingredients:
			[
				{ingredient:"Cheese"},
				{ingredient:"Potato"},
				{ingredient:"Mayo"},
				{ingredient:"Beef"},
				{ingredient:"Garlic"},
				{ingredient:"Butter"}
			]
	}
];
//Test to retrieve single, specific entries:
//      console.info(recipes[1].ingredients[0].ingredient);


//Test to get/return the checked values of the checkboxes:
function selectedBoxes(form) {
	let selectedBoxesArr = [];
	let inputFields = form.getElementsByTagName('input');
	let inputFieldsNumber = inputFields.length;

	for(let i=0; i<inputFieldsNumber; i++) {
		if (
			inputFields[i].type == 'checkbox' &&
			inputFields[i].checked == true
		) selectedBoxesArr.push(inputFields[i].value);
	}
	return selectedBoxesArr;
}

var getRecipesButton = document.getElementById('getRecipesButton');
getRecipesButton.addEventListener("click", function(){
  let selectedCheckBoxes = selectedBoxes(this.form);
  let output = document.getElementById('output');
  let myRecipes = recipes.filter(r => 
    selectedCheckBoxes.every(s => 
       r.ingredients.some(i => i.ingredient == s)
    )
  );
  output.innerHTML = myRecipes.map(v => v.name + ': ' + v.ingredients.map(i => i.ingredient).join(', ')).join('<br>');
});
<form action = "" method = "">
	<input type = "checkbox" value = "Cheese">Cheese<br>
	<input type = "checkbox" value = "Tomato">Tomato<br>
	<input type = "checkbox" value = "Garlic">Garlic<br>
	<input type = "checkbox" value = "Bacon">Bacon<br>
	<input type = "checkbox" value = "Paprika">Paprika<br>
	<input type = "checkbox" value = "Onion">Onion<br>
	<input type = "checkbox" value = "Potato">Potato<br>
	<input type = "checkbox" value = "Mayo">Mayo<br>
	<input type = "checkbox" value = "Beef">Beef<br>
	<input type = "checkbox" value = "Garlic">Garlic<br>
	<input type = "checkbox" value = "Butter">Butter<br>

	<input type = "button" value = "Get recipes" id = "getRecipesButton">
</form>

<div id = "output">The results end up here</div>

Здорово! Это работает, хотя не выводит ингредиенты, а выводит только тот, который соответствует, а не все.

Streching my competence 10.02.2019 15:45

@Strechingmycompetence извините за это - я недостаточно внимательно прочитал вопрос. Просто для полноты я обновил ответ, чтобы дать запрошенный вами результат.

Nick 10.02.2019 23:46

Нет стресса! Мне нравится разнообразие подходов к этому. Это дает мне надежду на будущее и мотивацию продолжать учиться :D

Streching my competence 11.02.2019 00:06

Я отредактировал ваш код и уменьшил его, а также добавил getRecipe, который будет возвращать рецепты.

//Recipes JSON-string:
var recipes = [
    {
        name:"recipe1",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Tomato"},
                {ingredient:"Garlic"}
            ]
    },
    {
        name:"recipe2",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Bacon"},
                {ingredient:"Paprika"},
                {ingredient:"Onion"}
            ]
    },
    {
        name:"recipe3",
        ingredients:
            [
                {ingredient:"Cheese"},
                {ingredient:"Potato"},
                {ingredient:"Mayo"},
                {ingredient:"Beef"},
                {ingredient:"Garlic"},
                {ingredient:"Butter"}
            ]
    }
];

function selectedBoxes(form) {
    let selectedBoxesArr = [];
    let inputFields = form.getElementsByTagName('input');
    // get all checked input values
    var checked = [...inputFields].filter((item) => item.checked == true
    ).map((item) => item.value)
    return checked;
}

// Validate the checked ingredients and get the recipes
function getRecipe(ingredients){
var recipe = [];
recipes.forEach((item)=> {
var found= false;
for(var ingredient in ingredients){
   var y = ingredients[ingredient]
   found= item.ingredients.filter((x) =>  x.ingredient.indexOf(y) != -1).length>0;
  if (!found)
      break;
    }
  if (found)
     recipe.push(item.name +":"+ item.ingredients.map((x)=> x.ingredient).join(", "));
});
return recipe;
}

var getRecipesButton = document.getElementById('getRecipesButton');
getRecipesButton.addEventListener("click", function(){
    let selectedCheckBoxes = selectedBoxes(this.form);
    console.info(getRecipe(selectedCheckBoxes))
});
<form action = "" method = "">
    <input type = "checkbox" value = "Cheese">Cheese<br>
    <input type = "checkbox" value = "Tomato">Tomato<br>
    <input type = "checkbox" value = "Garlic">Garlic<br>
    <input type = "checkbox" value = "Bacon">Bacon<br>
    <input type = "checkbox" value = "Paprika">Paprika<br>
    <input type = "checkbox" value = "Onion">Onion<br>
    <input type = "checkbox" value = "Potato">Potato<br>
    <input type = "checkbox" value = "Mayo">Mayo<br>
    <input type = "checkbox" value = "Beef">Beef<br>
    <input type = "checkbox" value = "Garlic">Garlic<br>
    <input type = "checkbox" value = "Butter">Butter<br>

    <input type = "button" value = "Get recipes" id = "getRecipesButton">
</form>

<div id = "output">The results end up here</div>

Спасибо! Я проголосовал за ваш ответ, так как он является полезен и кое-чему меня научил, хотя кажется, что он возвращает только первый найденный рецепт и массивы для остальных.

Streching my competence 10.02.2019 14:39

Другие вопросы по теме