Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CheckboxMultipleInput does not render form-invalid #85

Closed
XeonZenn opened this issue May 4, 2021 · 7 comments · Fixed by #92
Closed

CheckboxMultipleInput does not render form-invalid #85

XeonZenn opened this issue May 4, 2021 · 7 comments · Fixed by #92

Comments

@XeonZenn
Copy link

XeonZenn commented May 4, 2021

<input class="form-check-input #ADD ERROR HERE"

on each form-check-input the error should be displayed

I'll update this if I figure out where this code gets generated.

It's super hack-y but this works added to the end of renderers.py

html = format_html(
            '<{tag} class="{wrapper_classes}">{label}{field_with_help_and_errors}</{tag}>',
            tag=WRAPPER_TAG,
            wrapper_classes=self.get_wrapper_classes(),
            label=label,
            field_with_help_and_errors=field_with_help_and_errors,
        )
        if isinstance(self.widget,CheckboxSelectMultiple):
            addition = None
            if self.field_errors:
                addition = self.error_css_class
            elif self.field.form.is_bound:
                addition = self.success_css_class
            if addition:
                html = html.replace('<input class="form-check-input','<input class="form-check-input {addition}'.format(addition=addition))
                html = format_html(html)
        return html
@XeonZenn XeonZenn changed the title Multicheckbox does not render form-invalid CheckboxMultipleInput does not render form-invalid May 4, 2021
@dyve
Copy link
Member

dyve commented May 5, 2021

We could start with a test that fails. What's the expected output?

@dyve
Copy link
Member

dyve commented May 5, 2021

<div class="django_bootstrap5-error django_bootstrap5-required mb-3"><label class="form-label">Select2</label>
    <div class="form-check">
        <input class="form-check-input"
               type="checkbox"
               name="select2"
               id="id_select2_0"
               value="1"
        >
        <label class="form-check-label" for="id_select2_0">Radio 1</label>
    </div>
    <div class="form-check">
        <input class="form-check-input"
               type="checkbox"
               name="select2"
               id="id_select2_1"
               value="2"
        >
        <label class="form-check-label" for="id_select2_1">Radio 2</label>
    </div>
    <div class="form-text">Check as many as you like.</div>
    <div class="invalid-feedback">This field is required.</div>
</div>

The error message is rendered but appears to be hidden by Bootstrap.

@XeonZenn
Copy link
Author

XeonZenn commented May 5, 2021

I'm assuming bootstrap doesn't know what to do with the overall div
<div class="is-invalid mb-3"></div>
is how it currently gets rendered.
I've played with changing the order and class but I haven't had success yet.

In order for each individual checkbox to turn red the result on each input should be

<div class="form-check">
        <input class="form-check-input is-invalid"

@XeonZenn
Copy link
Author

XeonZenn commented May 5, 2021

Found the issue,
The <div class="form-check"> should be <div class="form-check is-invalid">

It would be best to add the is-invalid/is-valid wherever this initially gets formed, could you point me to the correct location in the code?

This code added to the end will fix it

html = format_html(
            '<{tag} class="{wrapper_classes}">{label}{field_with_help_and_errors}</{tag}>',
            tag=WRAPPER_TAG,
            wrapper_classes=self.get_wrapper_classes(),
            label=label,
            field_with_help_and_errors=field_with_help_and_errors,
        )
        if isinstance(self.widget,CheckboxSelectMultiple):
            if self.field_errors:
                html = html.replace('<input class="form-check-input','<input class="form-check-input {addition}'.format(addition=self.error_css_class))
                html = html.replace('<div class="form-check">','<div class="form-check {addition}">'.format(addition=self.error_css_class))
                html = format_html(html)
            elif self.field.form.is_bound:
                html = html.replace('<input class="form-check-input','<input class="form-check-input {addition}'.format(addition=self.success_css_class))
                html = html.replace('<div class="form-check">','<div class="form-check {addition}">'.format(addition=self.success_css_class))
                html = format_html(html)

        return html

Investigation:
wanted edit is set here:

            if isinstance(widget, (RadioSelect, CheckboxSelectMultiple)):
                widget.template_name = "django_bootstrap5/widgets/radio_select.html"

@dyve
Copy link
Member

dyve commented May 6, 2021

The problem is in the subwidgets. I have a first fix that at least makes the error message display, but it would be nice to get the individual inputs to become is-invalid as well.

@XeonZenn
Copy link
Author

XeonZenn commented May 6, 2021

I think the best way might be to pass the validity argument to the template through the widget class. I'll look into it tomorrow.

@XeonZenn
Copy link
Author

XeonZenn commented May 6, 2021

The good news is that the validity is already stored in widget.attrs['class'] which is passed to the template:

if we update django_bootstrap5/templates/django_bootstrap5/widgets/radio_select.html to the following it works!
There is no need for any of the code mentioned above

{% for group, options, index in widget.optgroups %}
    {% if group %}<div>{{ group }}</div>{% endif %}
    {% for option in options %}
        <div class="form-check {{widget.attrs.class}}">
            <input class="form-check-input {{widget.attrs.class}}"
                   type="{{ option.type }}"
                   name="{{ option.name }}"
                   id="{{ option.attrs.id }}"
                    {% if option.value != None %} value="{{ option.value|stringformat:'s' }}"
                        {% if option.attrs.checked %} checked="checked"{% endif %}{% endif %}>
            <label class="form-check-label {{widget.attrs.class}}" for="{{ option.attrs.id }}">{{ option.label }}</label>
        </div>
    {% endfor %}
{% endfor %}

@XeonZenn XeonZenn closed this as completed May 6, 2021
@XeonZenn XeonZenn reopened this May 13, 2021
@dyve dyve closed this as completed in #92 May 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants