web-dev-qa-db-fra.com

Comment insérer un formulaire Django dans la fenêtre modale Twitter-bootstrap?

Quelqu'un a demandé exactement même question en avril, sans aucune réponse. Mais puisqu'il a fourni trop peu d'informations; la question a été abandonnée.

J'ai le même problème. Dans un main_page.html J'ai cette ligne:

<a href="/contact/edit/{{ item.id }}" title="Edit">edit</a>

Une fois que vous y avez cliqué, le modèle d'édition doit apparaître dans un modal Twitter bootstrap.

url.py

(r'^contact/edit/(?P<contact_id>\d+)/$', contact_view),

view.py

def contact_view(request, contact_id=None):
    profile = request.user.get_profile()
    if contact_id is None:
        contact = Contact(company=profile.company)
        template_title = _(u'Add Contact')
    else:
        contact = get_object_or_404(profile.company.contact_set.all(), pk=contact_id)
        template_title = _(u'Edit Contact')
    if request.POST:
        if request.POST.get('cancel', None):
            return HttpResponseRedirect('/')
        form = ContactsForm(profile.company, request.POST, instance=contact)
        if form.is_valid():
            contact = form.save()
            return HttpResponseRedirect('/')
    else:
        form = ContactsForm(instance=contact, company=profile.company)
    variables = RequestContext(request, {'form':form, 'template_title': template_title})
    return render_to_response("contact.html", variables)

Voici généralement à quoi ressemblerait le contact.html :

        <form class="well" method="post" action=".">
            {% csrf_token %}
            {{form.as_p}}
            <input class="btn btn-primary" type="submit" value="Save" />
            <input name="cancel" class="btn" type="submit" value="Cancel"/>
        </form>

Je pourrais mettre ça dans un <div class="modal-body">. Mais alors comment puis-je ouvrir le modal de la vue?

34
Houman

Sauf si vous devez utiliser le formulaire de contact en dehors du modal, cela devrait fonctionner pour vous. Si vous devez l'utiliser ailleurs, conservez deux versions (une modale, une non). En outre, un conseil - donnez Django-crispy-forms une recherche - il vous aide à rendre les formulaires avec les classes Twitter-bootstrap.

contact.html:

<div class="modal hide" id="contactModal">
<form class="well" method="post" action="/contact/edit/{{ item.id }}">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal">×</button>
    <h3>Editing Contact</h3>
  </div>
  <div class="modal-body">
       {% csrf_token %}
       {{form.as_p}}
  </div>
  <div class="modal-footer">
       <input class="btn btn-primary" type="submit" value="Save" />
       <input name="cancel" class="btn" type="submit" value="Cancel"/>
  </div>
</form>
</div>

main_page.html

<html>
...

<a data-toggle="modal" href="#contactModal">Edit Contact</a>

{% include "contact.html" %}

...
</html>

Modifier:

Ok, maintenant que je sais que vous avez potentiellement plusieurs formulaires, c'est probablement une mauvaise idée de rendre chaque formulaire caché dans le html. Vous voudrez probablement passer à une version ajax-y et charger chaque formulaire à la demande. Je suppose ici que lors de la soumission du formulaire, la page entière se rechargera. Si vous souhaitez soumettre le formulaire de manière asynchrone, il existe des réponses ailleurs .

Nous allons commencer par redéfinir le contact.html fragment. Il doit être rendu dans un modal et contenir tout le balisage nécessaire pour jouer à Nice avec le modal. La vue contact que vous avez à l'origine est correcte - sauf que si le formulaire est invalide, vous finirez par rendre le contact.html et rien d'autre.

<form class="well contact-form" method="post" action="/contact/edit/{{ item.id }}">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal">×</button>
    <h3>Editing Contact</h3>
  </div>
  <div class="modal-body">
       {% csrf_token %}
       {{form.as_p}} <!-- {{form|crispy}} if you use Django-crispy-forms -->
  </div>
  <div class="modal-footer">
       <input class="btn btn-primary" type="submit" value="Save" />
       <input name="cancel" class="btn" type="submit" value="Cancel"/>
  </div>
</form>

Et maintenant, votre main_page.html:

<html>
.. snip ..

<a class="contact" href="#" data-form="/contact/edit/{{ item.id }}" title="Edit">edit</a>
<a class="contact" href="#" data-form="/contact/edit/{{ item.id }}" title="Edit">edit</a>
<a class="contact" href="#" data-form="/contact/edit/{{ item.id }}" title="Edit">edit</a>

<div class="modal hide" id="contactModal">
</div>

<script>
    $(".contact").click(function(ev) { // for each edit contact url
        ev.preventDefault(); // prevent navigation
        var url = $(this).data("form"); // get the contact form url
        $("#contactModal").load(url, function() { // load the url into the modal
            $(this).modal('show'); // display the modal on url load
        });
        return false; // prevent the click propagation
    });

    $('.contact-form').live('submit', function() {
        $.ajax({ 
            type: $(this).attr('method'), 
            url: this.action, 
            data: $(this).serialize(),
            context: this,
            success: function(data, status) {
                $('#contactModal').html(data);
            }
        });
        return false;
    });
</script>

.. snip ..
</html>

Tout cela n'a pas été testé, mais cela devrait vous donner un bon point de départ/itération.

43
Josh Smeaton

J'avais le même problème lorsque je rencontre ce message. J'ai essayé cette solution mais ça ne marchait pas vraiment pour moi (mais ça m'a donné une direction). J'ai trouvé une solution qui fonctionne pour moi, mais cela semble hacky et j'aimerais recevoir des conseils sur la façon de mieux le faire.

Le problème est le même: afficher un formulaire dans Twitter boostrap modal et Django (éditer/ajouter un modèle pour moi en utilisant Django vues de formulaire génériques))

Alors ce que j'ai fait:

main.html

<script type="text/javascript">
    function genericLoadDialog(form_selector, dialog_selector, matchString){
        $.ajax({
            url: $(form_selector).attr('action'),
            type: 'POST',
            data:  $(form_selector).serialize(),
            success: function(data, textStatus, jqXHR){
                if(data.match(matchString)){
                // We got errors in form
                    $(dialog_selector).html(data).modal('show');
                            return false;
                }
                        $(dialog_selector).modal('hide');
            },
        })
    }
</script>

<body>
<div class="modal hide" id="{{ editor_dialog_id }}"></div>
<a data-toggle="modal" href="#{{ editor_dialog_id }}" onclick="$('#{{ editor_dialog_id }}').load('/create/form');">Title</a>
<body>

editor.html

<form id="{{ editor_form_id }}" action="{{ submit_url }}" method="POST">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">×</button>
        <h3>Modal header</h3>
    </div>
    <div class="modal-body" id="editor-dialog-body">
        {% if not form.is_valid %}
            <div class='hide'>invalid_form</div>
        {% endif %}
        {% csrf_token %}
        {{ form.as_p }}
    </div>
    <div class="modal-footer">
       <a href="#" class="btn" data-dismiss="modal">Cancel</a>
       <a href="#" data-toggle="modal" class="btn btn-primary" onclick="genericLoadDialog('#{{ editor_form_id }}', '#{{ editor_dialog_id }}', null, 'invalid_form');">Save</a>
    </div>
</form>

Donc, le flux est le suivant:

  • cliquez sur la balise charge le formulaire à partir de l'URL du formulaire de création dans la division modale
  • cliquez sur le bouton Enregistrer en modal (soumettre) qui déclenche la fonction genericLoadDialog. Ce chargement fait une demande POST à l'url du formulaire de création avec les données collectées à partir du formulaire
  • Si le formulaire n'est pas valide, il recharge le HTML modal et affiche les champs d'erreur, sinon ferme le modal et Django devrait enregistrer/rediriger (j'utilise la méthode get_success_url dans Django = vue formulaire mais ne fonctionne pas pour moi pour une raison quelconque. Il enregistre l'objet)

Je suis mal à l'aise avec la façon dont je vérifie si le formulaire est valide ou non dans genericLoadDialog, si quelqu'un a une meilleure idée, ce serait bien.

1
Pablo Klijnjan