How to: Templates and Their Form Context as Dialog Box/Modals Instead of Pages?

Getting distracted by the one-page app allure again, there are some forms in my app that might be better suited in pop-ups or bootstrap components. The project has sign in and sign up pages, dished out with the standard practice of views that render templates for these pages with the forms as context. The forms and views are in an accounts app. And in another app there are multiple views that render pages that link to these with “sign in,” and “sign up,” links.

How can the app keep the user on whichever page they clicked these links on? So they click “sign in,” or “sign up,” and an HTML box or a bootstrap modal is opened with the forms? The project is using django.contrib.auth, not customizing any of that.

That would need to be done by some JavaScript code. That code would issue the get for the appropriate HTML fragment (as a dialog box, it’s not going to be a complete page), and use the response to populate the div that will be used as the bootstrap modal.

1 Like

Ty but what would that look like in a [class based] view, to listen for that GET and then sending a HttpResponse that is an HTML fragment with said form?

The same as any other class-based view.

The only difference is that the template you’re going to render would be the contents for the modal dialog box and not a complete page.

1 Like

It worked Ken! Thanks! I’ll post the code…

The Script in the Index Template

{% block script %}
<script>
    const signinBtn = document.getElementById("signinBtn")

    //there is a <dialog></dialog> at top of HTML body
    const dialog = document.querySelector('dialog')

    //the url is to a seperate app but it still works
    //and the form works, post method and all 
    fetch("{% url 'users:login' %}") 
        .then(response => response.text())
        .then(html => {
            dialog.innerHTML = html;
        })

    //pop up script
    signinBtn.addEventListener("click", (event) => {
        dialog.showModal();
    })
</script>
{% endblock %}

The Equivalent jQuery is

{% block script %}
<script>
    $(document).ready(function () {
        var dialog = $("dialog");
        //this builds the <dialog> element at page load
        $.get("{% url 'users:login' %}", function (data) {
            dialog.html(data);
        });

        $('#signinBtn').on('click', function () {
            dialog.show();
        });
    });
</script>
{% endblock %}

The only change I had to make to the template was make sure <form> </form> were the outermost parts, no more inheriting the base_generic.html. The view did not have to be changed at all. I’m pretty shocked, I expected this to be a lot more complicated. Starting to really appreciate Django.

Another option it’s use htmx for this, it’s a great replacement library and dev experience.

1 Like