0

ive a problem. in my template i want to click on parts of ingredients to select them by changing their id and when I'm clicking on a button I want the page to show all reciepes where the ingredients are in. Everything works for me. I can select ingredients and send the ajax request to my views.py and select all the reciepes with those ingredients and here comes my problem.

I am not able to reload the page without lopsing my context data from the ajax post request I hope i could discribe my problem

here ist the part of my views.py:

def what_to_cook(request):
    recipes = Recipe.objects.all()
    ingredients=Ingredients.objects.order_by().values('ingredient_name').distinct()
    context = {'recipes':recipes, 'ingredients':ingredients}

    if request.is_ajax():
        tasks = request.POST.getlist('marked_ingredients[]')
        selected = Ingredients.objects.filter(ingredient_name__in=tasks)
        print(selected)
        context = {'recipes':recipes, 'ingredients':ingredients,'tasks':tasks, 'selected':selected}
        return render(request, "/cooking/what_to_cook.html", context)
    else:
        return render(request, "cooking/what_to_cook.html", context)

And here is my template:

{% extends 'main/base.html' %}
{% load main_tags %}

{% block head %}
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'cooking.css' %}">
{% endblock %}

{% block title %}Kochen?!{% endblock %}
{% block subtitle %}Was koche ich heute?{% endblock %}

{% block content %}

<input type="text" id="myInput" onkeyup="search()" placeholder="Suche Zutaten ..." title="Type in a name">
<ol id="Zutaten">
{% for ingredient in ingredients|dictsort:"ingredient_name" %}
    <li class="element" id="not_marked" onclick="done(this)">{{ingredient.ingredient_name}}</li>
{% endfor %}
</ol>
<button onclick="build_array()">Gespannt auf den Vorschlag?</button>
{% for part in selected %}
    {{part}}
{% endfor %}
<p>{{selected}}</p>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script>
    function done(value) {
        console.log(value.id);
        if (value.id == "is_marked") {
            value.setAttribute("id", "not_marked");
            value.style.color="black";
        } else {
            value.setAttribute("id", "is_marked");
            value.style.color="green";
        }
    }
    function build_array() {
        var $marked_ingredients = document.querySelectorAll("[id='is_marked']");
        var i;
        marked_ingredients = []
        for (i = 0; i < $marked_ingredients.length; i++) {
          marked_ingredients.push($marked_ingredients[i].innerText);
        }
        console.log(marked_ingredients)
        var csrftoken = $("[name=csrfmiddlewaretoken]").val();
        $.ajax({
            type:'POST',
            url:'/cooking/what_to_cook',
            data: {'csrfmiddlewaretoken': '{{csrf_token}}',
            'marked_ingredients[]':marked_ingredients}
        });
    }

    function search() {
        var input, filter, ul, li, a, i, txtValue;
        input = document.getElementById("myInput");
        filter = input.value.toUpperCase();
        ul = document.getElementById("Zutaten");
        li = ul.getElementsByClassName("element")
        for (i = 0; i < li.length; i++) {
            txtValue = li[i].textContent || li[i].innerText;
            if (txtValue.toUpperCase().indexOf(filter) > -1) {
                li[i].style.display = "";
            } else {
                li[i].style.display = "none";
            }
        }
    }

</script>
{% endblock %}

UPDATE I got it to work with this kinde of code

TableItem +='<tr>' +
'<td><a href="/cooking/'+value.recipe_id+'">'+value.recipe_id+'</a></td>'+
                                        '<td>'+value.recipe_id+'</td>'+
                                        '<td>'+value.recipe_id+'</td>'+
                                        '</tr>'
                    $('#myTable').html(TableItem);

But is there a possibility to include this into a string to display it in the template above

{% for recipe in recipes %}
    {% if recipe.id == value.recipe_id %}
        {{recipe.title}}
    {% endif %}
{% endfor %}
MikeMike
  • 27
  • 3

1 Answers1

0

It looks like the line below in your views.py method if request.is_ajax() should be changed.

return render(request, "/cooking/what_to_cook.html", context)

You are rendering the entire template again on this call which defeats the purposed of making an AJAX request.

I am thinking you may want to use HttpResponse for the AJAX request instead of render.

Something like the following returning json for only the data needed:

if request.is_ajax():
    tasks = request.POST.getlist('marked_ingredients[]')
    selected = Ingredients.objects.filter(ingredient_name__in=tasks)
    print(selected)
    context = {'tasks':tasks, 'selected':selected}
    return HttpResponse(json.dumps(context, indent=4, sort_keys=True, default=str), content_type='application/json')

Then in your template script add a success function to handle the result:

function build_array() {
    var $marked_ingredients = document.querySelectorAll("[id='is_marked']");
    var i;
    marked_ingredients = []
    for (i = 0; i < $marked_ingredients.length; i++) {
      marked_ingredients.push($marked_ingredients[i].innerText);
    }
    console.log(marked_ingredients)
    var csrftoken = $("[name=csrfmiddlewaretoken]").val();
    $.ajax({
        type:'POST',
        url:'/cooking/what_to_cook',
        data: {'csrfmiddlewaretoken': '{{csrf_token}}',
        'marked_ingredients[]':marked_ingredients},
        success:   function(result){
                      for (var i = result.length - 1; i >= 0; i--) {
                         //do what you need to with the data
                         //for example add options to a select box
                          $("#select_id").append('<option>'+ result[i].ingredients.your_ingredient +'</option>');
                      };
                   },
    });
}

Hopefully this sends you down the right path.

JSS
  • 174
  • 9
  • Thanks for your answer but do you know how i can use the date in my html template? I get nothing with {{selected}} or {{tasks}} – MikeMike Dec 10 '20 at 17:57
  • You will need to use the 'result' returned to then apply to html. I added a small example of populating a select with options from the returned result. #select_id is the name of an html element you want to populate, and result[i].ingredients.your_ingredient to add data – JSS Dec 10 '20 at 18:48
  • Thanks i will try it tomorrow The "problem" is that i learnd python just by doing it and im at the very beginning with javascript and this website stuff – MikeMike Dec 10 '20 at 19:57
  • Same here. Here is another link to a very similar post that might help. It basically shows how to use JQuery and AJAX with django to make a request to a view and return a response, and handle it in the html. if you copy this code and play around with it, I think you will find it is pretty easy. https://stackoverflow.com/a/65150627/13795545 – JSS Dec 11 '20 at 16:30