bonjour je fais un site web pour un projet de fin d annee
c est un site qui consiste à calculer les prix d une recette
jai crée la page recettes.html et la page calculator.html
pr afficher les recettes jai utlisé une api themealdb,
je veux selectionner une recette (nom ingredients et recette, instructions, quantité utlisé)
et envoyez les donnees dans un tableau du fichier calculator (comportant des colonnees pr les ingredients, nom recette, quantité utlisé, instructions)
jai utlisé le localstorage et je rencontre bcp d erreurs ,
jai utlisé flask sessions : pareil
j utlise mysql, python flask, html, css, js vanilla)

<!DOCTYPE html>
<html>
<head>
  <title>Calculator</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
  <!-- Inclure les liens vers les fichiers CSS de la barre latérale et des ingrédients -->
  <link rel="stylesheet" href="static/css/dashboard.css">

  <link href="https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet" />
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

</head>
<body>
  <h2>Calculator</h2>

  <div id="sidebar">
    <!-- Contenu de la barre latérale depuis dashboard.css -->
  </div>
  <div id="content-container">

 <form id="recipe-calculator-desktop">
        <table>
            <thead>
                <tr>
                    <th colspan="3">Recette</th>
                    <th colspan="3">Méthode</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td colspan="3">
                        <label for="f_name"><strong>Nom de la recette</strong></label>
                        <input type="text" id="f_name" name="f_name">
                    </td>
                    <td colspan="3" rowspan="2">
                        <label for="method"><strong>Ajoutez votre méthode</strong></label>
                        <textarea id="method" name="method"></textarea>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label for="f_servings"><strong>Nombre de portions</strong></label>
                        <input type="number" name="f_servings" min="1" value="1">
                    </td>
                </tr>
                <tr>
                    <td colspan="6"><h1>Ingrédients</h1></td>
                </tr>
                <tr class="ingredient-heading">
                    <td colspan="2" class="col-33">Nom de l'ingrédient</td>
                    <td class="col-16">Qté achetée</td>
                    <td class="col-16">Coût des marchandises</td>
                    <td class="col-16">Qté utilisée dans la recette</td>
                    <td class="col-16">Coût total</td>
                </tr>
                <tr id="row_1" class="ingred-row">
                    <td colspan="2">
                        <input type="text" name="f_ingredients_1" placeholder="Nom de l'ingrédient">
                    </td>
                    <td>
                        <input type="number" step="any" name="f_quantity_1" placeholder="g / mL / each" min="0" data-row-qty>
                    </td>
                    <td>
                        <input type="number" step="any" name="f_cost_1" placeholder="$" min="0" data-row-cost>
                    </td>
                    <td>
                        <input type="number" step="any" name="f_used_1" placeholder="g / mL / each" min="0" data-row-used>
                    </td>
                    <td class="total-cost">
                        <input type="text" name="f_total_1" placeholder="$0.00" readonly data-cost>
                    </td>
                </tr>
                <!-- Répétez ces lignes pour d'autres ingrédients -->
                <tr>
                    <td colspan="6">Coût total de la recette :</td>
                    <td id="grandTotal" placeholder="$0.00">$0.00</td>
                </tr>
            </tfoot>
        </table>
        <button type="button" data-add>+ Ajouter un ingrédient supplémentaire</button>
        <button type="submit">Envoyer</button>
    </form>
<!-- ... autres balises HTML ... -->
<div>
    <ul>
    {% for ingredient in recipe.ingredients %}
      <li>{{ ingredient }}</li>
    {% endfor %}
    </ul>
    <h1>Recette Sélectionnée</h1>

<ul>
<h1>{{ recipe.recipe_name }}</h1>
<ul>
{% for ingredient in recipe.ingredients %}
    <li>{{ ingredient.strip() }}</li>
{% endfor %}
</ul>
<p>{{ recipe.instructions }}</p>

</div>
<!-- ... autres balises HTML ... -->

    <script>
    let rowNumber = 1; // On commence avec une ligne

    // Ajout d'ingrédient supplémentaire
    document.querySelector("button[type='button']").addEventListener('click', function() {
        rowNumber++;
        let newRow = `
        <tr id="row_${rowNumber}" class="ingred-row">
            <td colspan="2">
                <input type="text" name="f_ingredients_${rowNumber}" placeholder="Nom de l'ingrédient">
            </td>
            <td>
                <input type="number" step="any" name="f_quantity_${rowNumber}" min="0">
                <select name="f_unit_${rowNumber}">
                    <option value="g">g</option>
                    <option value="mg">mg</option>
                    <option value="L">L</option>
                    <option value="mL">mL</option>
                    <option value="kilo">kilo</option>
                </select>
            </td>
            <td>
                <input type="number" step="any" name="f_cost_${rowNumber}" placeholder="€" min="0">
            </td>
            <td>
                <input type="number" step="any" name="f_used_${rowNumber}" min="0">
                <select name="f_used_unit_${rowNumber}">
                    <option value="g">g</option>
                    <option value="mg">mg</option>
                    <option value="L">L</option>
                    <option value="mL">mL</option>
                    <option value="kilo">kilo</option>
                </select>
            </td>
            <td>
                <input type="text" name="f_total_${rowNumber}" placeholder="€0.00" readonly>
            </td>
        </tr>`;

        let tbody = document.querySelector("tbody");
        tbody.insertAdjacentHTML('beforeend', newRow);
    });

    // Lorsqu'un ingrédient est sélectionné, mis à jour du coût des marchandises
    document.querySelectorAll("select[name^='f_ingredients']").forEach(select => {
        select.addEventListener('change', function(event) {
            const selectedRowNumber = event.target.name.match(/\d+/)[0]; // Obtenir le numéro de la ligne
            const ingredientName = event.target.value;
            const costInput = document.querySelector(`input[name="f_cost_${selectedRowNumber}"]`);
            costInput.value = getIngredientPrice(ingredientName);
            calculateTotal();
        });
    });

    // changements dans les quantités et mis à jour le coût total
    document.querySelectorAll("input[name^='f_quantity']").forEach(input => {
        input.addEventListener('input', calculateTotal);
    });

    document.querySelectorAll("input[name^='f_used']").forEach(input => {
        input.addEventListener('input', calculateTotal);
    });

    // Soumission du formulaire pour le calcul
    document.getElementById("recipe-calculator-desktop").addEventListener('submit', function(event) {
        event.preventDefault();
        calculateTotal();
    });

    // Fonction pour calculer le coût total
    function calculateTotal() {
        let grandTotal = 0;
        for (let i = 1; i <= rowNumber; i++) {
            let quantity = parseFloat(document.querySelector(`[name="f_quantity_${i}"]`).value);
            let unit = document.querySelector(`[name="f_unit_${i}"]`).value;
            let cost = parseFloat(document.querySelector(`[name="f_cost_${i}"]`).value);
            let used = parseFloat(document.querySelector(`[name="f_used_${i}"]`).value);

            // Conversion d'unité
            switch (unit) {
                case "mg":
                    quantity /= 1000; // Convertir mg en g
                    break;
                case "L":
                    quantity *= 1000; // Convertir L en mL
                    break;
                case "kilo":
                    quantity *= 1000; // Convertir kilo en g
                    break;
            }

            if (!isNaN(quantity) && !isNaN(cost) && !isNaN(used)) {
                let total = (cost / quantity) * used;
                document.querySelector(`[name="f_total_${i}"]`).value = `€${total.toFixed(2)}`;
                grandTotal += total;
            }
        }

        // Mis à jour du coût total 
        document.getElementById("grandTotal").textContent = `€${grandTotal.toFixed(2)}`;
    }

    // Charger les détails de la recette
    // Fonction pour charger les détails de la recette depuis le stockage local
    function loadRecipeDetails() {
        const recipeDetails = JSON.parse(localStorage.getItem('recipeDetails'));
        if (recipeDetails) {
            document.getElementById("f_name").value = recipeDetails.name;
            document.getElementById("method").value = recipeDetails.method;

            recipeDetails.ingredients.forEach((ingredient, index) => {
                if (index >= 1) {
                    addNewRow();
                }
                document.querySelector(`[name="f_ingredients_${index+1}"]`).value = ingredient.name;
                document.querySelector(`[name="f_quantity_${index+1}"]`).value = ingredient.quantity;
                document.querySelector(`[name="f_cost_${index+1}"]`).value = ingredient.cost;
                document.querySelector(`[name="f_used_${index+1}"]`).value = ingredient.used;
            });
        }
    }
// Ajoutez des écouteurs d'événements pour ajouter des lignes, soumettre le formulaire, etc.
    document.querySelector("button[type='button']").addEventListener('click', addNewRow);
    document.getElementById("recipe-calculator-desktop").addEventListener('submit', function(event) {
        event.preventDefault();
        let recipeDetails = {
        name: document.getElementById("f_name").value,
        method: document.getElementById("method").value,
        ingredients: []
    };

    for (let i = 1; i <= rowNumber; i++) {
        let ingredient = {
            name: document.querySelector(`[name="f_ingredients_${i}"]`).value,
            quantity: document.querySelector(`[name="f_quantity_${i}"]`).value,
            cost: document.querySelector(`[name="f_cost_${i}"]`).value,
            used: document.querySelector(`[name="f_used_${i}"]`).value,
        };
        recipeDetails.ingredients.push(ingredient);
    }

    localStorage.setItem('recipeDetails', JSON.stringify(recipeDetails));
});
    // Appeler la fonction lors du chargement de la page
    document.addEventListener('DOMContentLoaded', loadRecipeDetails);

    // Appeler la fonction lors de la soumission du formulaire
    document.getElementById("recipe-calculator-desktop").addEventListener('submit', function(event) {
        event.preventDefault();
        calculateTotal();
    })
    // Récupérer les ingrédients sélectionnés depuis le stockage local
const selectedIngredients = JSON.parse(localStorage.getItem("selectedIngredients"));

// Utiliser les ingrédients sélectionnés pour effectuer les calculs nécessaires
if (selectedIngredients) {
    for (const ingredient of selectedIngredients) {
        const newRow = $("<tr>");
        newRow.append('<td><i class="fas fa-edit editIcon"></i> <i class="fas fa-trash-alt deleteIcon"></i></td>');
        newRow.append(`<td>${ingredient.name}</td>`);
        newRow.append(`<td>${ingredient.unit_cost}</td>`);
        newRow.append(`<td>${ingredient.stock_quantity}</td>`);
        $("#ingredientTable tbody").append(newRow);
    }
}

// Effacer les ingrédients sélectionnés du stockage local après les avoir utilisés
localStorage.removeItem("selectedIngredients");

    document.addEventListener('DOMContentLoaded', async () => {
        const response = await fetch('/get_selected_recipe');
        if (response.ok) {
            const recipe = await response.json();
            // Utilisez les données de la recette ici pour les afficher sur la page
            // par exemple :
            document.getElementById('recipe-name').textContent = recipe.name;
            document.getElementById('recipe-ingredients').innerHTML = recipe.ingredients.map(
                ingredient => `<li>${ingredient}</li>`
            ).join('');
        } else {
            console.error('Failed to fetch recipe:', response.statusText);
        }
    });
</script>

</body>
</html>

voici le fichier calculator.html

<!DOCTYPE html>
<html>
<head>
    <title>Recettes</title>
    <!-- CSS pour Font Awesome, Dashboard et Boxicons  boostrap-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <link rel="stylesheet" href="static/css/dashboard.css">
   <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">

    <link href="https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet"/>
    <!-- jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

</head>
<body>
 <div class="container mt-3">
        <header>
            <h1 class="text-center">Look a Recipe</h1>
        </header>
        <h1 class="text-center">Cuisine pour tous</h1>
        <div class="input-group my-3">
            <input type="text" class="form-control rounded-pill" placeholder="Entrez le nom d'une recette" id="searchInput">
            <button class="btn btn-primary rounded-pill" id="searchRecipe">Rechercher</button>
        </div>
        <div id="results">
            Entrez le nom d'une recette pour commencer la recherche.
        </div>
        <div id="recipeDetails" style="display: none;" class="mt-3">
    <h2>Détails de la recette</h2>
    <div id="recipeName"></div>
    <div id="recipeIngredients"></div>
    <div id="recipeInstructions"></div>
    <div id="recipeImages" class="d-flex flex-wrap justify-content-center gap-2"></div>
    <form id="recipeForm" action="/set_selected_recipe" method="POST">
        <!-- Vos champs de formulaire ici -->
        <button type="submit" class="btn btn-primary mt-3" id="goToCalculatorButton">Sélectionner cette recette</button>
    </form>
    <a href="{{ url_for('calculator') }}" id="calculator-link-from-recettes" class="btn btn-secondary mt-3">Aller vers Calculatrice</a>
</div>

    </div>
    <script>
        const searchInput = document.getElementById("searchInput");
        const searchRecipeBtn = document.getElementById("searchRecipe");
        const results = document.getElementById("results");
        const recipeDetails = document.getElementById("recipeDetails");
        const recipeName = document.getElementById("recipeName");
        const recipeIngredients = document.getElementById("recipeIngredients");
        const recipeInstructions = document.getElementById("recipeInstructions");
        const recipeImages = document.getElementById("recipeImages");

        let selectedRecipe = null;

        const searchRecipe = async () => {
            const searchQuery = searchInput.value.trim();
            if (searchQuery === "") {
                results.innerHTML = "Entrez le nom d'une recette pour commencer la recherche.";
                return;
            }
            const response = await fetch(`https://www.themealdb.com/api/json/v1/1/search.php?s=${searchQuery}`);
            const data = await response.json();
            if (data.meals) {
                results.innerHTML = "";
                data.meals.forEach((meal) => {
                    const recipeItem = document.createElement("div");
                    recipeItem.classList.add("recipe-item");
                    recipeItem.innerHTML = `<h3>${meal.strMeal}</h3>`;
                    recipeItem.addEventListener("click", () => showRecipeDetails(meal.idMeal));
                    results.appendChild(recipeItem);
                });
            } else {
                results.innerHTML = "Aucun résultat trouvé.";
            }
        };

        const showRecipeDetails = async (recipeId) => {
            recipeImages.innerHTML = '';
            const response = await fetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${recipeId}`);
            const data = await response.json();

            if (data.meals && data.meals[0]) {
                const meal = data.meals[0];
                recipeName.textContent = meal.strMeal;
                recipeIngredients.innerHTML = `<h4>Ingrédients:</h4> ${getIngredientsList(meal)}`;
                recipeInstructions.innerHTML = `<h4>Instructions:</h4> ${meal.strInstructions}`;

                const recipeImage = document.createElement("img");
                recipeImage.src = meal.strMealThumb;
                recipeImages.appendChild(recipeImage);

                const ingredientsElements = getIngredientsImages(meal);
                ingredientsElements.forEach((ingredientElement) => {
                    recipeImages.appendChild(ingredientElement);
                });

                recipeDetails.style.display = "block";
                selectedRecipe = {
                    name: meal.strMeal,
                    ingredients: getIngredientsList(meal),
                    instructions: meal.strInstructions
                };
            }
        };

        const getIngredientsImages = (meal) => {
            const ingredientsElements = [];
            for (let i = 1; i <= 20; i++) {
                if (meal[`strIngredient${i}`] && meal[`strMeasure${i}`]) {
                    const ingredientName = meal[`strIngredient${i}`];
                    const ingredientContainer = document.createElement("div");
                    ingredientContainer.classList.add("ingredient-container");

                    const ingredientImage = document.createElement("img");
                    ingredientImage.src = `https://www.themealdb.com/images/ingredients/${ingredientName}.png`;
                    ingredientImage.classList.add("ingredient-img");
                    ingredientContainer.appendChild(ingredientImage);

                    const ingredientQuantity = document.createElement("span");
                    ingredientQuantity.classList.add("ingredient-quantity");
                    ingredientQuantity.textContent = meal[`strMeasure${i}`];
                    ingredientContainer.appendChild(ingredientQuantity);

                    ingredientsElements.push(ingredientContainer);
                }
            }
            return ingredientsElements;
        };

        const getIngredientsList = (meal) => {
            let ingredientsList = "";
            for (let i = 1; i <= 20; i++) {
                if (meal[`strIngredient${i}`]) {
                    ingredientsList += `${meal[`strIngredient${i}`]}: ${meal[`strMeasure${i}`]}<br>`;
                }
            }
            return ingredientsList;
        };

        searchRecipeBtn.addEventListener("click", searchRecipe);

    document.getElementById("goToCalculatorButton").addEventListener("click", () => {
    if (selectedRecipe) {
        fetch("/set_selected_recipe", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(selectedRecipe)
        })
        .then(response => response.json())
        .then(data => {
            window.location.href = "/calculator";
        })
        .catch(error => {
            console.log(error);
        });
    }
});
    </script>
</body>
</html>

python server.py

def get_recipe_from_db(recipe_id):
    cur = mysql.connection.cursor()
    cur.execute("SELECT * FROM recettes WHERE id=%s", [recipe_id])
    recipe = cur.fetchone()
    cur.close()
    return recipe

@app.route('/recettes')
def recettes():
    return render_template('recettes.html')

@app.route('/set_selected_recipe', methods=['POST'])
def set_selected_recipe():
    selected_recipe = request.get_json()

    if selected_recipe is None:
        return jsonify({'message': 'Invalid JSON'}), 400

    session['selected_recipe'] = json.dumps(selected_recipe, ensure_ascii=False)
    return jsonify({'message': 'Recipe details stored in session'})

@app.route("/calculator", methods=["GET", "POST"])
def calculator():
    recipe = {
        "name": "",
        "ingredients": [],
        "instructions": "",
        "quantity_used": ""
    }

    if 'selected_recipe' in session:
        recipe_json_string = session.get('selected_recipe')
        recipe_data = json.loads(recipe_json_string)
        recipe['name'] = recipe_data.get('name')
        recipe['ingredients'] = recipe_data.get('ingredients', [])
        recipe['instructions'] = recipe_data.get('instructions', "")
        recipe['quantity_used'] = recipe_data.get('quantity_used', "")

    return render_template("calculator.html", recipe=recipe)

@app.route('/get_recipe/<int:recipe_id>', methods=['GET'])
def get_recipe(recipe_id):
    recipe_data = {
        'recipe_id': recipe_id,
        'recipe_name': 'Nom de la recette',
        'ingredients': ['Ingrédient 1', 'Ingrédient 2', 'Ingrédient 3'],
    }
    return jsonify(recipe_data)

@app.route('/api/recipe_details/<int:recipe_id>', methods=['GET'])
def get_recipe_details(recipe_id):
    cur = mysql.connection.cursor()
    cur.execute("SELECT * FROM recettes WHERE id=%s", [recipe_id])
    recipe = cur.fetchone()
    cur.close()

    return jsonify(recipe)

@app.route('/select_recipe', methods=['POST'])
def select_recipe():
    data = request.json

    session['selectedRecipe'] = {
        'name': data['name'],
        'ingredients': data['ingredients'],
        'instructions': data['instructions']
    }

    return jsonify(success=True)

Ce que je veux

recuperez les donnees d une recette , la stocker pr l envoyer à calculator.html

Ce que j'obtiens
j obtiens des erreurs de cookies

les erreurs "Unsupported Media Type

Did not attempt to load JSON data because the request Content-Type was not 'application/json'. "

3 réponses


Beaucoup trop de code, essaie de simplifier ta question en ne mettrant que le strict nécessaire :(

samsam00
Auteur

je veux juste collecter des donnees de la recette (nom de la recette, nom des ingredients, quantité utlisé ) vers le calculator.html

recettes.html

localStorage.removeItem("selectedIngredients");

document.addEventListener('DOMContentLoaded', async () => {
    const response = await fetch('/get_selected_recipe');
    if (response.ok) {
        const recipe = await response.json();
        // Utilisez les données de la recette ici pour les afficher sur la page
        // par exemple :
        document.getElementById('recipe-name').textContent = recipe.name;
        document.getElementById('recipe-ingredients').innerHTML = recipe.ingredients.map(
            ingredient => `<li>${ingredient}</li>`
        ).join('');
    } else {
        console.error('Failed to fetch recipe:', response.statusText);
    }
});

et calculator.html
les donnees doivent etre inserés ds le tableau

document.getElementById("goToCalculatorButton").addEventListener("click", () => {
if (selectedRecipe) {
fetch("/set_selected_recipe", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(selectedRecipe)
})
.then(response => response.json())
.then(data => {
window.location.href = "/calculator";
})
.catch(error => {
console.log(error);
});
}
});

Pour ton fetch il faut ajouter une en tête "Accept" pour indiquer tu veux du JSON