Search code examples
pythondjangohtmx

htmx:targetError with {% block content %}


im using htmx with Django. I have the problem, as soon as i add my

{% extends base.html' %}
{% load static %}

{% block content %}
{% endblock content %}

the hx-target leads to a htmx:targetError.

This works (search_results.html):

<h1>Search Results</h1>

{% if results %}
    <ul>
    {% for supplier in results %}
        <li>
            <strong>Supplier Number:</strong> {{ supplier.supplier_number }}<br>
            <strong>Name:</strong> {{ supplier.name }}<br>
            <strong>Street:</strong> {{ supplier.street }}<br>
            <!-- Weitere Felder hier einfügen -->
            <a href="{% url 'supplychainmanagement:add_order' %}?supplier_name={{ supplier.name }}" class="select-supplier" hx-get="{% url 'supplychainmanagement:add_order' %}?supplier_name={{ supplier.name }}" hx-target="#bestellungen-list" hx-boost>Lieferant auswählen</a>
        </li>
    {% endfor %}
    </ul>
{% else %}
    <p>No results found.</p>
{% endif %}

** this doesnt** (search_results.html):

{% extends 'base.html' %}
{% load static %}

{% block content %}

<h1>Search Results</h1>

{% if results %}
    <ul>
    {% for supplier in results %}
        <li>
            <strong>Supplier Number:</strong> {{ supplier.supplier_number }}<br>
            <strong>Name:</strong> {{ supplier.name }}<br>
            <strong>Street:</strong> {{ supplier.street }}<br>
            <!-- Weitere Felder hier einfügen -->
            <a href="{% url 'supplychainmanagement:add_order' %}?supplier_name={{ supplier.name }}" class="select-supplier" hx-get="{% url 'supplychainmanagement:add_order' %}?supplier_name={{ supplier.name }}" hx-target="#bestellungen-list" hx-boost>Lieferant auswählen</a>
        </li>
    {% endfor %}
    </ul>
{% else %}
    <p>No results found.</p>
{% endif %}

{% endblock content %}

this is my base.html:

<!DOCTYPE html>
<html lang="en">

{% load static %}
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <style type="text/css">
        div.weiterrunter {
            margin-top: 40px
        }

    </style>
    <script src="{% static 'js/htmx.min.js' %}" defer></script>
</head>
<body>
    <div class = "container weiterrunter">

    {% include 'navbar.html' %}

    {% block content %}
        <!--    replace me-->
    {% endblock content%}

    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>


</body>
</html>

the Target is order_create.html:

{% extends 'base.html' %}
{% load static %}

{% block content %}

<h1>Bestellungen</h1>
<ul id="bestellungen-list">
    {% for bestellung in bestellungen %}
    <li>{{ bestellung.supplier }}</li>
    <ul>
        {% for item in bestellung.orderitem_set.all %}
        <li>{{ item.article }} - Menge: {{ item.quantity }}</li>
        {% endfor %}
    </ul>
    {% endfor %}
</ul>

<form action="{% url 'supplychainmanagement:search' %}" method="POST">
    {% csrf_token %}
    <input type="text" name="name" placeholder="Name">
    <input type="text" name="supplier_number" placeholder="Supplier Number">
    <input type="submit" name="submit" value="Search">
</form>


{% for result in results %}
<p>{{result.name}}</p>
<p>{{result.supplier_number}}</p>
{% endfor %}


<form hx-post="{% url 'supplychainmanagement:add_order' %}" hx-target="#bestellungen-list" hx-trigger="submit" hx-boost>
    {% csrf_token %}
    <label for="supplier">Lieferant:</label>
    <input type="text" name="supplier" id="supplier-input" placeholder="Supplier" value="{{ selected_supplier }}"
           required>
    <br>
    <div class="article-inputs">
        <label for="article">Artikel:</label>
        <select name="article">
            {% for article in articles %}
            <option value="{{ article.pk }}">{{ article.name }}</option>
            {% endfor %}
        </select>
        <label for="quantity">Menge:</label>
        <input type="number" name="quantity" placeholder="Menge" required>
    </div>
    <!-- Set the value of the selected_supplier input -->
    <input type="hidden" name="selected_supplier" id="selected-supplier" value="{{ selected_supplier }}">
    <br>
    <button type="button" hx-get="{% url 'supplychainmanagement:add_article_position' %}" hx-trigger="click"
            hx-swap="beforeend" hx-target=".article-inputs:last-of-type">Weitere Artikelposition hinzufügen
    </button>
    <button type="submit">Neue Bestellung hinzufügen</button>
</form>

{% endblock content %}

Can anybody lead me to the right direction or describe, why this happens?

i want to add a supplier.name to the supplier field in order_create.html

without the django typical extension tags ({% extends 'base.html' %},{% load static %},{% block content %} etc.) it works without any Problems


Solution

  • When you specify the hx-target, htmx expects the target element to be present in the DOM at the time you make the request. Because htmx works by updating DOM with the returned HTML from your server without refreshing the page, it needs to know where to put it. If it doesn't find the target, it throws that error.

    The reason the first snipet works is because htmx is not available in the page (because you're including htmx in your base.html, it is basically means htmx will not be available in the search_results.html, hence you think it works (because htmx is not available to alert you of the error). But as soon as you extend base.html, htmx becomes available in your the search_results.html, and is able to evaluate your code and sees there's no element with that ID (since that element is in in a different template, order_create.html.

    Looking at your templates, I think you have a confusing setup. If you want to target #estellungen-list, make sure it is in the same template as search_results.html. I could give you an example code if I knew how your application works. I looked at order_create.html, and I am quite frankly confused with how it's supposed to work. Perhaps you can provide your views.py with all the relevant view functions/classes that are interacting with your templates.