Modals with simple content

Possiamo riempire il contenuto della dialog invocando via Ajax una vista che restituisca l’opportuno frammento HTML:

<a href=""
   data-action="{% url 'frontend:simple-content' %}"
   data-title="Simple content"
   data-subtitle="Modal content is obtained via Ajax call"
   data-icon="fa-keyboard-o"
   data-button-save-label="Save"
   onclick="openMyModal(event); return false;">
    <i class="fa fa-keyboard-o"></i> Modal with simple content
</a>
<script language="javascript">

    function openMyModal(event) {
        var modal = initModalDialog(event, '#modal_generic');
        var url = $(event.target).data('action');
        modal.find('.modal-body').load(url, function() {
            modal.modal('show');
        });
    }

</script>
def simple_content(request):
    return HttpResponse('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dignissim dapibus ipsum id elementum. Morbi in justo purus. Duis ornare lobortis nisl eget condimentum. Donec quis lorem nec sapien vehicula eleifend vel sit amet nunc.')
../_images/modal_with_simple_content_1.png

Si osservi come abbiamo specificato l’url della view remota nell’attributo “data-action” del trigger.

Questa soluzione e’ preferibile rispetto all’utilizzo di href per evitare che, in caso di errori javascript il link, il link invochi direttamente la view, compromettendo quindi l’intera pagina o inserendo nel corpo della dialog contenuti inappropriati.

Un limite del codice precedente e’ che non siamo in grado di rilevare eventuali errori del server, nel qual caso la dialog verrebbe comunque aperta (con contenuto vuoto).

Il problema viene facilmente superato invocando direttamente $.ajax() anziche’ lo shortcut load().

La soluzione e’ leggermente piu’ verbose, ma consente un controllo piu’ accurrato:

<script language="javascript">

    function openMyModal(event) {
        var modal = initModalDialog(event, '#modal_generic');
        var url = $(event.target).data('action');
        $.ajax({
            type: "GET",
            url: url
        }).done(function(data, textStatus, jqXHR) {
            modal.find('.modal-body').html(data);
            modal.modal('show');
        }).fail(function(jqXHR, textStatus, errorThrown) {
            alert("SERVER ERROR: " + errorThrown);
        });
    }

</script>
def simple_content_forbidden(request):
    raise PermissionDenied
../_images/server_error_detected.png

More flexible server side processing

A volte puo’ essere utile riutilizzare la stessa view per fornire, a seconda delle circostanze, una dialog modale oppure una pagina standalone.

La soluzione proposta prevede l’utilizzo di templates differenziati nei due casi:

def simple_content2(request):

    # Either render only the modal content, or a full standalone page
    if request.is_ajax():
        template_name = 'frontend/includes/simple_content2_inner.html'
    else:
        template_name = 'frontend/includes/simple_content2.html'

    return render(request, template_name, {
    })

dove il template “inner” fornisce il contenuto:

<div class="row">
    <div class="col-sm-4">
        {% lorem 1 p random %}
    </div>
    <div class="col-sm-4">
        {% lorem 1 p random %}
    </div>
    <div class="col-sm-4">
        {% lorem 1 p random %}
    </div>
</div>

mentre il template “esterno” si limita a includerlo nel contesto piu’ completo previsto dal frontend:

{% extends "base.html" %}
{% load static staticfiles i18n %}

{% block content %}
{% include 'frontend/includes/simple_content2_inner.html' %}
{% endblock content %}
../_images/modal_with_simple_content_2.png

Modal dialog

../_images/modal_with_simple_content_2_standalone.png

Same content in a standalone page

Note

Check sample code at: (5) Modal with simple content