Rending a separate page dynamically using django and htmx

Am working on a simple task app using Django and HTMX. I want when a user clicks on a button in the navbar to add a task, the add task page should be displayed dynamically without causing a page reload. Yes the task page gets displayed dynamically but when i try to reload my page Some content of the page gets lost. Checkout below the code snippets

navbar.html

{% load static %}

<div class="flex justify-between pt-10 pb-3">
    <div class="w-6/12">
        <div class="font-bold text-gray-700 text-2xl" style="cursor: pointer;">Task Manager</div>
    </div>
    <div class="w-1/12 text-gray-500" style="cursor: pointer;">Home</div>
    <div class="w-1/12 text-gray-500" style="cursor: pointer;">Pending</div>
    <div class="w-1/12 text-gray-500" style="cursor: pointer;">Complete</div>
    <div class="w-1/12 text-gray-500" style="cursor: pointer;">Pricing</div>
    <div class="w-1/12 text-gray-500">
        <div class="flex justify-center items-center">
        <a role="button" class="bg-blue-700 rounded text-white font-bold text-sm px-4 py-1" href="{% url "create_todo" %}" hx-get="{% url "create_todo" %}" hx-push-url="true" hx-target="#main">Add Task</a>
        </div>
    </div>
    <div class="w-1/12 text-gray-500">
        <div class="flex justify-center items-center">
            <img src="{% static 'images/me.jpg' %}" alt="Profile" srcset="" class="rounded-full w-12 h-12">
        </div>  
    </div>
</div>
<hr>

home.html

{% extends "../base.html" %}

{% block title %}Home Board{% endblock title %}

{% block content %}
    {% include "./navbar.html" %}
    <div class="px-20" id="main">
        <div class="flex justify-between">
            <h3 class="mt-5 text-center text-xl text-gray-500 font-bold my-8">Today's Tasks</h3>
            <div class="flex justify-center items-center">
                <button class="bg-blue-700 rounded text-white font-bold text-sm px-4 py-1">View Calendar</button>
            </div>
        </div>
        <div class="flex">
            <div class="flex justify-center items-center">
                <button class="bg-blue-700 rounded text-white font-bold text-sm px-4 py-1">All</button>
            </div>
            <div class="flex justify-center items-center ml-4">
                <button class="bg-blue-700 rounded text-white font-bold text-sm px-4 py-1">Completed</button>
            </div>
            <div class="flex justify-center items-center ml-4">
                <button class="bg-blue-700 rounded text-white font-bold text-sm px-4 py-1">Incomplete</button>
            </div>
        </div>

        <div id="all-tasks">
            {% include "./todo-list.html" %}
        </div>
        <div id="completed-tasks">
        </div>
        <div id="incomplete-tasks">
        </div>
    </div>
            </form>
        </div> 
    </div>
<div>
    
</div>

{% endblock content %}

views.py

def create_todo(request):
    if request.method == "POST":
        title = request.POST.get("title")
        description = request.POST.get("description")
        due_date = request.POST.get("due_date")
        todo = Todo.objects.create(title=title, description=description, due_date=due_date)
        # todo.save()

        todos = Todo.objects.all().order_by("-id")
        context = {
            "todos": todos,
        }
        return render(request, "todo/todo-list.html", context)
    elif request.method == "GET":
        return render(request, "todo/add_task.html")

add_task.html

<div class="flex justify-center">
    <div class="w-full">New Task</div>
    <div>
        <label for="title">Task Title</label>
        <input type="text" name="title" id="title">
    </div>
</div>

When the page is rendered, it looks like belowImage showing the add_task page rendered dynamically

When i try to reload the page, the contents of the page change to image of the add_task page after me trying to reload it

I thought after reloading the page, the contents on it would remain the same

The way to solve it is to provide entire html template when "non-htmx" request is done.

So in your view, check if request is triggered by htmx and if not, use different template (one that includes add_task.html and extends from base.html)

elif request.method == "GET":
    if request.headers.get("HX-Request") == "true":
        return render(request, "todo/add_task.html")
    
    return render(request, "todo/add_task_with_base.html")
Back to Top