Skip to content

Commit

Permalink
Added BS4 is-valid class on validation for checkbox, radio, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
smithdc1 authored and carltongibson committed Sep 19, 2019
1 parent 2c41dbc commit 5eb5548
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 25 deletions.
6 changes: 3 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 %}form-check{% 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 %}custom-control custom-checkbox{% 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,8 @@

{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="form-check-label{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field 'class' 'form-check-input' %}
{% crispy_field field 'class' 'custom-control-input' %}
<label for="{{ field.id_for_label }}" class="custom-control-label{% 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
@@ -1,19 +1,19 @@
{% load crispy_forms_filters %}
{% load l10n %}

<div class="{% if inline_class %}form-check{% endif %}{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
<div class="{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>

{% for choice in field.field.choices %}
{% if not inline_class %}<div class="form-check">{% endif %}
<input type="checkbox" class="form-check-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="form-check-{% if inline_class %}{{ inline_class }}{% else %}label{% endif %}" for="id_{{ field.html_name }}_{{ forloop.counter }}">
<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 }}">
{{ choice.1|unlocalize }}
</label>
{% if field.errors and forloop.last %}
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% endif %}
{% if not inline_class %}</div>{% endif %}
{% endfor %}
{% endif %}
</div>
{% endfor %}

{% include 'bootstrap4/layout/help_text.html' %}
</div>
10 changes: 5 additions & 5 deletions crispy_forms/templates/bootstrap4/layout/radioselect.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{% load crispy_forms_filters %}
{% load l10n %}

<div class="{% if inline_class %}form-check{% endif %}{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
<div class="{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>

{% for choice in field.field.choices %}
{% if not inline_class %}<div class="form-check">{% endif %}
<input type="radio" class="form-check-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="form-check-{% if inline_class %}{{ inline_class }}{% else %}label{% endif %}">
<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">
{{ choice.1|unlocalize }}
</label>
{% if field.errors and forloop.last %}
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% endif %}
{% if not inline_class %}</div>{% endif %}
</div>
{% endfor %}

{% include 'bootstrap4/layout/help_text.html' %}
Expand Down
4 changes: 2 additions & 2 deletions crispy_forms/templatetags/crispy_forms_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ def render(self, context):

if (
template_pack == 'bootstrap4'
and not is_checkbox(field)
and not is_multivalue(field)
):
css_class += ' form-control'
if not is_checkbox(field):
css_class += ' form-control'
if field.errors:
css_class += ' is-invalid'

Expand Down
6 changes: 4 additions & 2 deletions crispy_forms/tests/test_form_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ def test_inputs(settings):
assert 'class="btn"' in html
assert 'btn btn-primary' in html
assert 'btn btn-inverse' in html
assert len(re.findall(r'<input[^>]+> <', html)) == 8

if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert len(re.findall(r'<input[^>]+> <', html)) == 9
else:
assert len(re.findall(r'<input[^>]+> <', html)) == 8

def test_invalid_form_method():
form_helper = FormHelper()
Expand Down
2 changes: 1 addition & 1 deletion crispy_forms/tests/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ def test_keepcontext_context_manager(settings):
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert response.content.count(b'checkbox-inline') == 3
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert response.content.count(b'form-check-inline') == 3
assert response.content.count(b'custom-control-inline') == 3


@only_bootstrap3
Expand Down
10 changes: 5 additions & 5 deletions crispy_forms/tests/test_layout_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ class CustomCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
form.helper = FormHelper()
form.helper.layout = Layout('inline_radios')

html = render_crispy_form(form)
html = render_crispy_form(form)
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert 'class="form-check"' in html
assert 'class="custom-control-input"' in html
else:
assert 'class="radio"' in html

Expand All @@ -161,7 +161,7 @@ class CustomCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
form.helper.layout = Layout('checkboxes')
html = render_crispy_form(form)
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert 'class="form-check"' in html
assert 'class="custom-control-input"' in html
else:
assert 'class="checkbox"' in html

Expand Down Expand Up @@ -225,7 +225,7 @@ def test_inline_radios(self, settings):
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert html.count('radio-inline"') == 2
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count('form-check-inline"') == 2
assert html.count('custom-control-inline"') == 2

def test_accordion_and_accordiongroup(self, settings):
test_form = SampleForm()
Expand Down Expand Up @@ -487,7 +487,7 @@ def test_multiplecheckboxes(self, settings):
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert html.count('checkbox-inline"') == 3
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count('form-check-inline"') == 3
assert html.count('custom-control-inline"') == 3

def test_multiple_checkboxes_unique_ids(self):
test_form = CheckboxesSampleForm()
Expand Down

0 comments on commit 5eb5548

Please sign in to comment.