DataTable table ordering fails when used in HTMX responsive table

I have played around with a few ways to create responsive tables and I like the htmx approach. The issue I run into is I loose some of the DataTables functions I have relied upon, mainly the ability for the user to sort by clicking on the header.

Views.py:

    class HomePageView(TemplateView):
        template_name = 'wwdb/home_tabletest.html'
    
    class WinchOperatorForm(forms.ModelForm):
        class Meta:
            model = WinchOperator
            exclude = []
    
    def get_winchoperator_list(request):
        context = {}
        context['winchoperator'] = WinchOperator.objects.all()
        return render(request, 'wwdb/winchoperator_list.html', context)
    
    def add_winchoperator(request):
        context = {'form': WinchOperatorForm()}
        return render(request, 'wwdb/add_winchoperator.html', context)
    
    def add_winchoperator_submit(request):
        context = {}
        form = WinchOperatorForm(request.POST)
        context['form'] = form
        if form.is_valid():
            context['winchoperator'] = form.save()
        else:
            return render(request, 'wwdb/add_winchoperator.html', context)
        return render(request, 'wwdb/winchoperator_row.html', context)
    
    def add_winchoperator_cancel(request):
        return HttpResponse()
    
    def delete_winchoperator(request, winchoperator_pk):
        winchoperator = WinchOperator.objects.get(pk=winchoperator_pk)
        winchoperator.delete()
        return HttpResponse()
    
    def edit_winchoperator(request, winchoperator_pk):
        winchoperator = WinchOperator.objects.get(pk=winchoperator_pk)
        context = {}
        context['winchoperator'] = winchoperator
        context['form'] = WinchOperatorForm(initial={
            'firstname':winchoperator.firstname,
            'lastname': winchoperator.lastname,
            'status': winchoperator.status,
            'username': winchoperator.username,
        })
        return render(request, 'wwdb/edit_winchoperator.html', context)
    
    def edit_winchoperator_submit(request, winchoperator_pk):
        context = {}
        winchoperator = WinchOperator.objects.get(pk=winchoperator_pk)
        context['winchoperator'] = winchoperator
        if request.method == 'POST':
            form = WinchOperatorForm(request.POST, instance=winchoperator)
            if form.is_valid():
                form.save()
            else:
                return render(request, 'wwdb/edit_winchoperator.html', context)
        return render(request, 'wwdb/winchoperator_row.html', context)

I can post more templates if requested, but the template defining the tables are:


    <div>
        <table class="table display">
            <thead>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Status</th>
            <th>Username</th>
            <th>test</th>
            <th>test</th>
            </thead>
            <tbody>
                {% for winchoperator in winchoperator %}
                <tr>
                    <td>{{ winchoperator.firstname }}</td>
                    <td>{{ winchoperator.lastname }}</td>
                    <td>{{ winchoperator.status }}</td>
                    <td>{{ winchoperator.username }}</td>
                    <td>
                        <button class='btn'
                                hx-get="{% url 'edit_winchoperator' winchoperator.pk %}"
                                hx-target="closest tr"
                                hx-swap="outerHTML">
                            <svg class="bi bi-pencil" width="32" height="32">
                                <use xlink:href="#pencil">
                            </svg>
                        </button>
                    </td>
                    <td>
                        <button class='btn'
                                hx-confirm='Are you sure?'
                                hx-target="closest tr"
                                hx-swap="outerHTML swap:1s"
                                hx-delete="{% url 'delete_winchoperator' winchoperator.pk %}">
                            <svg class="bi bi-trash3" width="32" height="32">
                                <use xlink:href="#trash3">
                            </svg>
                        </button>
                    </td>
                </tr>            
                {% endfor %}
            </tbody>
        </table>
    </div>

    <!DOCTYPE html>
    <body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
        <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
            <symbol id="checkmark" viewBox="0 0 16 16">
                <path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425a.247.247 0 0 1 .02-.022Z" />
            </symbol>
            <symbol id="cancel" viewBox="0 0 16 16">
                <path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z" />
            </symbol>
            <symbol id="pencil" viewBox="0 0 16 16">
                <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z" />
            </symbol>
            <symbol id="trash3" viewBox="0 0 16 16">
                <path d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5ZM11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H2.506a.58.58 0 0 0-.01 0H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1h-.995a.59.59 0 0 0-.01 0H11Zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5h9.916Zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 1 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47ZM8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5Z" />
            </symbol>
            <symbol id="plus" viewBox="0 0 16 16">
                <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
            </symbol>
        </svg>
        <button class='btn'
                hx-get="{% url 'add_winchoperator' %}"
                hx-target="next tbody" 
                hx-swap="afterbegin">
            <svg class="bi bi-plus" width="32" height="32">
                <use xlink:href="#plus">
            </svg>
        </button>
        <div id="query_result"
             hx-target="this"
             hx-swap="innerHTML"
             hx-get="{% url 'get_winchoperator_list' %}"
             hx-trigger="load delay:1s">
        </div>
    </body>

The datatable class I am referring to is in my base.py file, which is loaded in the template.

    <script type="text/javascript">
        $(document).ready(function () {
            $('table.display').DataTable({
                autoWidth: false,
                scrollX: true
            });
            // Listen for Bootstrap tab activation event
            $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                // Get the DataTable instance of the active tab
                var activeTable = $($(e.target).attr('href')).find('table').DataTable();
                // Adjust columns when the tab becomes active
                activeTable.columns.adjust().draw();
            });
        });
    </script>

I used the following tutorial to get where I am now. Loved the tutorial but want to find a way to integrate it into the tables I already have in place.

https://medium.com/@duytran2310/django-crud-inside-a-table-with-htmx-part-1-53dd8417c36a
Back to Top