Search code examples
javascriptdjangodjango-formsbootstrap-modal

Django - Diplay a form in a modal


I'm building a Django application and I try to display one of my forms in a modal window. It has been initially developed for a normal one, the scripts worked fine, but I cannot manage implement properly the modal.
The context is classical: a window displays a list of objects with, for each of them, a button to edit it, and an additional global button to create a new object. Each button is supposed to open the same modal.
It could have become easy if I did not have several js scripts dedicated to the form, because they are my issue: the do not work properly now that the form is in a modal. So there is something I did wrong, and at the end I'm not even sure my approach is the best one.

First question: among my search, an idea could be that js script won't apply on html part updated afterwards: is it true? In this case, is there a way to make a kind of 'reload' to make js undertand its scope has changed?

The modal is displayed using bootstrap, HTML code is the following:

<div id="grp_detail" class="modal fade hide" role="dialog" tabindex='-1'>
    <div class="modal-dialog modal-lg">
        <div class="modal-content form_content">
            {% include './adm_group_detail.html' %}
        </div>
    </div>
</div>

Tell me if you need the included template - it's quite big because the form is a bit tricky.

The view that displays de page with the list is the following:

@user_passes_test(lambda u: u.is_superuser or (u.id is not None and u.usercomp.is_admin))
def adm_groups(request, comp_slug):
    '''
        Manage users groups
    '''
    # Variables set to be integrated in locals()
    company = Company.get_company(comp_slug)
    group_list = UserGroup.objects.filter(company__comp_slug=comp_slug, hidden=False).order_by('group_name')

    # Initialize an empty form to create a new group (to be displayed in a modal)
    group_form = GroupDetail()
    group_form.fields['all_users'].queryset = UserComp.objects.\
                                                filter(company=company).\
                                                order_by('user__last_name', 'user__first_name')


    return render(request, "polls/adm_groups.html", locals())

As you can see, I generate an empty form at this stage to ease the display when the user intends to create a new item.
In this case, the modal works perfectly. Unfortunately, I need to use the script to refresh the form if I have edited another item before; and, in this case, like you will see, it doesn't work.

To populate the form to edit an object, data is gathered thanks to a js script: The script to generate the form is the following:

    $('.update-grp').click(function(e) {
        $.ajax({
            method: 'GET',
            url: $(this).attr('url-endpoint'),
            data: {
                comp_slug: $(this).attr('comp-slug'),
                grp_id: $(this).attr('grp-id')
            },
            success: handleSuccess,
            error: handleError,
        });

        function handleSuccess(data) {
            $(".form_content").html(data.group_form);
        };

        function handleError(error_data) {
            console.log("error");
            console.log(error_data);
        };
    })

It calls the following view:

def get_group_detail(request):
    """ Gather and send information related to groups """

    comp_slug = request.GET["comp_slug"]
    grp_id = int(request.GET["grp_id"])   # comes as string when 0
    company = Company.get_company(comp_slug)

    if grp_id > 0:
        current_group = UserGroup.objects.get(id=grp_id)
        group_form = GroupDetail(instance=current_group)
    else:
        group_form = GroupDetail()
        group_form.fields['all_users'].queryset = UserComp.objects.\
                                                    filter(company=company).\
                                                    order_by('user__last_name', 'user__first_name')

    context = {
        "comp_slug": comp_slug,
        "company": company,
        "grp_id": grp_id,
        "group_form": group_form,
    }

    template = render_to_string('polls/adm_group_detail.html', context=context, request=request)

    return JsonResponse({"group_form": template})

The modal is displayed properly but the scripts related to the form are not launched at all (even a console.log('Hello') do no display anything).

Among my tries, one of them was to generate the whole template not only, the one dedicated to the form, but the result was just worse.

For your information, I don't know it it could help, here is a view of the modal with data: enter image description here

Blue buttons are designed to move elements from one list to the other, which is also possible thanks to a double click. But nothing happens at all within the modal.


Solution

  • What I latest felt was correct: the scripts do not apply to updated html code. To change this, I need to attach the handler to a parent object that will not change, then 'delegate' to the actual object that is supposed to trigger an action.

    Thus, I need to change how the buttons in the modal are triggered end replace this, where the handler is on the button itself:

    $("#add_selected").on("click", function(e) {
    

    with this, where the handler includes the modal, and delegate the event to the button:

    $(".form_content").on("click", '#add_selected', function(e) {