django-crispy-forms / django-crispy-forms

The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.
http://django-crispy-forms.rtfd.org
MIT License
5.02k stars 732 forks source link

Validation on tabbed forms with required fields #623

Closed J20S closed 7 years ago

J20S commented 8 years ago

Hi,

When we have a tabbed form with all fields required and we try to submit form with all empty fields except for current tab, then the validation for hidden fields (the fields not displayed under current tab) doesn't work properly as we get the following Jquery error in the console: An invalid form control with name='field_two' is not focusable. The ideal outcome would be the tab with empty fields gets navigated and error messages display.

To reproduce this problem: Say I have a very basic form as follows:

class ExampleForm(forms.Form):
    field_one = forms.CharField(required=True)
    field_two = forms.CharField(required=True)

    def __init__(self, *args, **kwargs):
        super(ExampleForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = \
            Layout(
                TabHolder(
                    Tab('First Tab',
                        'field_one',
                        ),
                    Tab('Second Tab',
                        'field_two',
                        )
                )
            )

And the following is my simple view:

def index(request):

    if request.method == 'POST':
        form = ExampleForm(request.POST)

        if form.is_valid():
            return render(request, 'demo/successful.html',
                          {'data': form.cleaned_data})
        else:
            return render(request, 'demo/successful.html',
                          {'data': form.errors})

    else:
        form = ExampleForm()

    context = {
        'form': form
    }

    return render(request, 'demo/crispy_form.html', context)

And the template:

{% load crispy_forms_tags %}
{% load static %}
<link href="{% static 'demo/bootstrap.css' %}" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="{% static 'demo/bootstrap-tab.js' %}"></script>

<form action="/demo/" method="post" enctype="multipart/form-data" class="uniForm">
{% crispy form %}
<input type="submit" value="Update Profile" class="button"/>
</form>

Is there any good workaround on this problem, or we need to manually add some Jquery to make it work as expected?

zoidyzoidzoid commented 8 years ago

The simplest solution would be separate views and forms for each tab.

sureshvv commented 7 years ago

I am facing the same issue. Seems to be a chrome bug.

Best solution seems to be to add novalidate in the form tag and let the server do the validation.

carltongibson commented 7 years ago

I'm going to close this. I don't think it's really a Crispy Forms issue

mpdehaan commented 6 years ago

While not a Crispy Forms issue, it prevents use of tabs in Crispy Forms in chrome for submitting one object broken into multiple tabs. A workaround would be awesome for those of us who don't know how to do it in Javascript.

Thoughts on workarounds? A form submit for every tab feels like a bad user experience.

Thanks!

mpdehaan commented 6 years ago

I fixed this by doing the following on load:

$("#editForm").attr('novalidate', 'novalidate');

Thanks to Stackoverflow, it will now switch forms. I have only tested this in Chrome but validation works for me!