jazzband / django-floppyforms

Full control of form rendering in the templates.
http://django-floppyforms.readthedocs.org/
Other
839 stars 145 forks source link

The "required" attribute should not be set for fields in an empty_permitted form #168

Open dylanmccall opened 8 years ago

dylanmccall commented 8 years ago

I am using Floppyforms in an elaborate form page consisting of several nested ModelForm objects, and some form sets. Some of these form sets have min_num=0, which causes the initial forms to be created with empty_permitted = True. That is, the server-side validation won't complain if the entire form is empty. Required fields are only enforced if the form has been modified. However, even for those forms, any fields marked as required are given the HTML5 required attribute, making it impossible to submit the form without filling them in.

Steps to reproduce:

import floppyforms as forms
class OptionalForm(forms.Form):
    name = forms.CharField(required=True)
optional_form = OptionalForm(empty_permitted=True)
print(optional_form.as_p().strip())

Expected output:

<p>
    <label for="id_name">Name:</label>
    <input type="text" name="name" id="id_name">

</p>

Actual output:

<p>
    <label for="id_name">Name:</label>
    <input type="text" name="name" required id="id_name">

</p>

Workaround

Here's a workaround I have been using. A complete solution also needs some JavaScript code that interprets data-was-required and does fun things:

class TKDModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(TKDModelForm, self).__init__(*args, **kwargs)    

        if self.empty_permitted:
            for key, field in self.fields.iteritems():
                if field.widget.is_required:
                    field.widget.is_required = False
                    field.widget.attrs.pop('required', None)
                    field.widget.attrs['data-was-required'] = True

This goes through every field in the form, and if the widget has been marked as required we make sure to strip the required attribute, set is_required = False (so it isn't passed to the widget's template), and then add our own attribute to keep track of this field's more complex validation rules.

gregmuellegger commented 8 years ago

Hm, I think I see the problem here. We have a server-side behaviour in the form (allow either all fields to be empty, unless at least one field is filled in, then require all to be filled in) that we cannot replicate with a html-only solution.

I would recommend adding the novalidate attribute to your <form> tag as described here: http://django-floppyforms.readthedocs.org/en/latest/differences.html#client-side-validation

But I know that this does not replicate the behaviour you expect. What would you suggest as a solution? Remove the <input required> attributes when empty_permitted=True?