Skip to content

Commit

Permalink
Make additional customization optional, applying it to BS4 customizat…
Browse files Browse the repository at this point in the history
…ion of radio and checkbox
  • Loading branch information
bryan-brancotte committed Sep 23, 2019
1 parent 5eb5548 commit 2db5d71
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 12 deletions.
2 changes: 2 additions & 0 deletions crispy_forms/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def helper(self):
template = None
field_template = None
disable_csrf = False
use_custom_control = True
label_class = ''
field_class = ''
include_media = True
Expand Down Expand Up @@ -364,6 +365,7 @@ def get_attributes(self, template_pack=TEMPLATE_PACK):
'html5_required': self.html5_required,
'form_show_labels': self.form_show_labels,
'disable_csrf': self.disable_csrf,
'use_custom_control': self.use_custom_control,
'label_class': self.label_class,
'field_class': self.field_class,
'include_media': self.include_media
Expand Down
10 changes: 7 additions & 3 deletions crispy_forms/templates/bootstrap4/field.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="{% for offset in bootstrap_checkbox_offsets %}{{ offset }} {% endfor %}{{ field_class }}">
{% endif %}
{% endif %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if not field|is_checkbox %}form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% else %}custom-control custom-checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if not field|is_checkbox %}form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% else %}{%if use_custom_control%}custom-control custom-checkbox{% else %}form-check{% endif %}{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and not field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="{% if 'form-horizontal' in form_class %}col-form-label {% endif %}{{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
Expand All @@ -26,8 +26,12 @@

{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
{% crispy_field field 'class' 'custom-control-input' %}
<label for="{{ field.id_for_label }}" class="custom-control-label{% if field.field.required %} requiredField{% endif %}">
{%if use_custom_control%}
{% crispy_field field 'class' 'custom-control-input' %}
{% else %}
{% crispy_field field 'class' 'form-check-input' %}
{% endif %}
<label for="{{ field.id_for_label }}" class="{%if use_custom_control%}custom-control-label{% else %}form-check-label{% endif %}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% include 'bootstrap4/layout/help_text_and_errors.html' %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@
<div class="{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>

{% for choice in field.field.choices %}
<div class="custom-control custom-checkbox{% if inline_class %} custom-control-inline{% endif %}">
<input type="checkbox" class="custom-control-input{%if is_bound %} is-{% if field.errors %}in{%endif%}valid{% endif %}"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
<label id="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="custom-control-label" for="id_{{ field.html_name }}_{{ forloop.counter }}">
<div class="{%if use_custom_control%}custom-control custom-checkbox{% if inline_class %} custom-control-inline{% endif %}{% else %}form-check{% if inline_class %} form-check-inline{% endif %}{% endif %}">
<input type="checkbox" class="{%if use_custom_control%}custom-control-input{% else %}form-check-input{% endif %}{%if is_bound %} is-{% if field.errors %}in{%endif%}valid{% endif %}"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
<label id="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="{%if use_custom_control%}custom-control-label{% else %}form-check-label{% endif %}" for="id_{{ field.html_name }}_{{ forloop.counter }}">
{{ choice.1|unlocalize }}
</label>
{% if field.errors and forloop.last %}
{% if field.errors and forloop.last and not inline_class %}
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
{% if field.errors and inline_class %}
<div class="w-100 {%if use_custom_control%}custom-control custom-checkbox{% if inline_class %} custom-control-inline{% endif %}{% else %}form-check{% if inline_class %} form-check-inline{% endif %}{% endif %}">
<input type="checkbox" class="custom-control-input {% if field.errors %}is-invalid{%endif%}">
{% include 'bootstrap4/layout/field_errors_block.html' %}
</div>
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% endif %}

{% include 'bootstrap4/layout/help_text.html' %}
</div>
6 changes: 3 additions & 3 deletions crispy_forms/templates/bootstrap4/layout/radioselect.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<div class="{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>

{% for choice in field.field.choices %}
<div class="custom-control custom-radio{% if inline_class %} custom-control-inline{% endif %}">
<input type="radio" class="custom-control-input{%if is_bound %} is-{% if field.errors %}in{%endif%}valid{% endif %}"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
<label for="id_{{ field.html_name }}_{{ forloop.counter }}" class="custom-control-label">
<div class="{%if use_custom_control%}custom-control custom-radio{% if inline_class %} custom-control-inline{% endif %}{% else %}form-check{% endif %}">
<input type="radio" class="{%if use_custom_control%}custom-control-input{% else %}form-check-input{% endif %}{%if is_bound %} is-{% if field.errors %}in{%endif%}valid{% endif %}"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
<label for="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="{%if use_custom_control%}custom-control-label{% else %}form-check-{% if inline_class %}{{ inline_class }}{% else %}label{% endif %}{% endif %}">
{{ choice.1|unlocalize }}
</label>
{% if field.errors and forloop.last %}
Expand Down
44 changes: 44 additions & 0 deletions crispy_forms/tests/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,50 @@ def test_keepcontext_context_manager(settings):
assert response.content.count(b'checkbox-inline') == 3
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert response.content.count(b'custom-control-inline') == 3
assert response.content.count(b'custom-checkbox') > 0


@only_bootstrap4
def test_use_custom_control_is_used():
form = CheckboxesSampleForm()
form.helper = FormHelper()
form.helper.layout = Layout(
'checkboxes',
InlineCheckboxes('alphacheckboxes'),
'numeric_multiple_checkboxes'
)
# form.helper.use_custom_control take default value which is True

response = render(
request=None,
template_name='crispy_render_template.html',
context={'form': form}
)
assert response.content.count(b'custom-control-inline') == 3
assert response.content.count(b'custom-checkbox') == 9

form.helper.use_custom_control = True

response = render(
request=None,
template_name='crispy_render_template.html',
context={'form': form}
)
assert response.content.count(b'custom-control-inline') == 3
assert response.content.count(b'custom-checkbox') == 9

form.helper.use_custom_control = False

response = render(
request=None,
template_name='crispy_render_template.html',
context={'form': form}
)

assert response.content.count(b'custom-control-inline') == 0
assert response.content.count(b'form-check-inline') == 3
assert response.content.count(b'form-check') > 0
assert response.content.count(b'custom-checkbox') == 0


@only_bootstrap3
Expand Down
3 changes: 3 additions & 0 deletions docs/form_helper.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ Helper attributes you can set
**disable_csrf = False**
Disable CSRF token, when done, crispy-forms won't use ``{% csrf_token %}`` tag. This is useful when rendering several forms using ``{% crispy %}`` tag and ``form_tag = False`` csrf_token gets rendered several times.

**use_custom_control = True**
It indicate whether the radio and checkbox button should use the optional UI customization of the template pack or not. Useful when you already have customization based on the default interpretation of the template pack. When enabled crispy-forms will render elements such as checkbox and radio with optional additional UI customization, when available. Defaults to ``True``.

**form_error_title**
If you are rendering a form using ``{% crispy %}`` tag and it has ``non_field_errors`` to display, they are rendered in a div. You can set the title of the div with this attribute. Example: “Form Errors”.

Expand Down

0 comments on commit 2db5d71

Please sign in to comment.