Heikkisorsa
Heikkisorsa

Reputation: 905

Preventing django form to refresh whole page on submit

I have a form in Django which is embedded in a bootstrap modal element. The input of the form is a client id which I check if it is in the database. Everything works fine on submit except that in case the client id is not in the database the page gets reloaded and I have to open the modal element again to see the error message.

I tried to simple prevent the page refresh by adding a script to my html:

$('#modalform').on('submit', function (e) {
        e.preventDefault();
    })

But this breaks the form behaviour on submit.

The modal div with the form in my home.html looks like this:

<div class="modal fade" tabindex="-1" role="dialog" id="mymodal" aria-labelledby="myLargeModalLabel">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-body">
                <form action="" method="POST" id="modalform">
                    {% csrf_token %}

                    {% if form.non_field_errors %}
                        <div class="alert alert-danger" role="alert">
                            {% for error in form.non_field_errors %}
                                {{ error }}
                            {% endfor %}
                        </div>
                    {% endif %}

                    {% for field in form.visible_fields %}
                        <div class="form-group">
                            {{ field.label_tag }}

                            {% if form.is_bound %}
                                {% if field.errors %}
                                    {% render_field field class="form-control is-invalid" %}
                                    {% for error in field.errors %}
                                        <div class="invalid-feedback">
                                            {{ error }}
                                        </div>
                                    {% endfor %}

                                 {% else %}
                                     {% render_field field class="form-control is-valid" %}
                                 {% endif %}
                             {% else %}
                                 {% render_field field  class="form-control" %}
                             {% endif %}
                         </div>
                     {% endfor %}

                <input class="btn btn-primary" type="submit" value="submit">
            </form>
        </div>
    </div>
</div>

The view in view.py looks like this:

def home(request):
    if request.method == "POST":
        print("POST")
        form = SelectClient(request.POST)

        if form.is_valid():
            url = reverse(
                "client",
                kwargs={"client_id": form.cleaned_data["client_id"]},
            )
            return HttpResponseRedirect(url)

    else:
        form = SelectClient()
        print("GET")

    return render(request, "app/home.html", {"form": form})

The form looks like this:

class SelectClient(forms.Form):
    client_id = forms.CharField(label="Client ID")

    def clean_client_id(self):
        data = self.cleaned_data["client_id"]

        if Client.objects.filter(client_id=data).exists():
            print("Success!")
        else:
            print("No such client!")
            raise ValidationError(
                _("No such client!")
            )

        return data

And urls.py looks like this:

urlpatterns = [
    path("", views.home, name="app-home"),
    path(
        "client/<str:client_id>",
        views.client,
        ),
]
  1. Can I achieve that on submit of a client_id which is not in the database the page does not fully reload and just updates the error message without using ajax?

  2. If not: How would the added ajax code look like, if I want the desired behaviour?

My first idea went to something like this:

$('#modalform').on('submit', function (e) {
        e.preventDefault();

        $.ajax({
            type: 'POST',
            url: '/home/',
            data: {
                client_id: $('#client_id').val(),
                csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val()
            },
            success: function () {
                alert("Client found, but what now?!");
            },
            error: function () {
                alert("Client not found, but what now?!")
            }
        })

    })

Upvotes: 0

Views: 3337

Answers (2)

Heikkisorsa
Heikkisorsa

Reputation: 905

As I found it hard to work with Django Forms in this case, I solved the problem more explicitly.

My new test_form form:

<form id="test_form">
    {% csrf_token %}
    <div class="form-group">
        <label for="client_id">Client ID:</label>
        <input class="form-control" id="client_id" placeholder="Client ID" />
        <div class="form-text text-danger" id="form-error"></div>
    </div>
    <input class="btn btn-primary" type="submit" value="submit">
</form>

My Javascript for the new test_form form:

$('#test_form').on('submit', function (e) {
        e.preventDefault();

        $.ajax({
            type: 'POST',
            url: 'ajax/testform/',
            data: {
                client_id: $('#client_id').val(),
                csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val()
            },
            success: function (data) {

                console.log(data["status"])
                if (data["status"] == "valid") {
                    window.location.href = "/client"
                }
                if (data["status"] == "invalid") {
                    $("#form-error").html(data["message"]);
                    $("#client_id").addClass("is-invalid")
                }
            },
            error: function () {
                alert("Error!")
            }
        })

    })

And the new testform view:

def testform(request):
    if request.method == "POST":
        form = SelectClient(request.POST)

        if request.is_ajax():
            if form.is_valid():
                data = {"status": "valid", "client_id": form.cleaned_data["client_id"]}

            else:
                data = {
                    "status": "invalid",
                    "client_id": form.data["client_id"],
                    "message": form.errors["client_id"],
                }
        else:
            data = {"message": "not an ajax call"}
        return JsonResponse(data)

Anything against this solution? Is this consider good practice?

Upvotes: 1

HenryM
HenryM

Reputation: 5793

You want to check if there are form errors (you could do a specific field) and pop the modal if there are

<script>
    {% if form.errors %}
        document.getElementById("mymodal").showModal(); 
    {% endif %}
</script>

Upvotes: 1

Related Questions