-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Improve handling of choice fields with no choices in form templates #17579
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
Comments
For this kind of issues, a screenshot of the error comes in very handy. Could you please provide one? Thanks! |
There is no error? |
@backbone87 you can just use the option |
@HeahDude i am talking about extended choices |
@backbone87 if you mean |
Choice with options (all fine) $form->add('categories', 'choice', array(
'choices_as_values' => true,
'choices' => array('A' => 'a'),
'multiple' => true,
'expanded' => true,
'required' => false,
)); HTML generated with bootstrap 3 layout <div class="form-group">
<label class="h4 control-label">Kategorien</label>
<div id="categories">
<div class="checkbox">
<label class="h4">
<input type="checkbox" id="categories_0" name="categories[]" value="a"> A
</label>
</div>
</div>
</div> Choice with no options $form->add('categories', 'choice', array(
'choices_as_values' => true,
'choices' => array(),
'multiple' => true,
'expanded' => true,
'required' => false,
)); HTML generated with bootstrap 3 layout <div class="form-group">
<label class="h4 control-label">Kategorien</label>
<div id="categories"></div>
</div> There are multiple things to consider:
empty_data does nothing presentation wise. what you mean is probably placeholder (formerly empty_value), which doesnt apply to multiple = true. but even with expanded = true and multiple = false providing a placeholder could, depending on the use case, confuse the user (it would be better to display a message, that no options are available to chose from) edit: ignore the h4 classes, they come from my form_row call (label_attr) |
@backbone87 I've found a workaround <?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ExtendedChoiceType extends ChoiceType
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
parent::buildView($view, $form, $options);
if (empty($view->vars['choices'])) {
$view->vars['empty_choices'] = $options['empty_choices'];
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('empty_choices', '<em>No choices available</em>');
parent::configureOptions($resolver);
}
} and then override the twig block with : {# when using form_div_layout.html.twig #}
{%- block choice_widget_expanded -%}
<div {{ block('widget_container_attributes') }}>
{%- for child in form %}
{{- form_widget(child) -}}
{{- form_label(child, null, {translation_domain: choice_translation_domain}) -}}
{% else %}
{{ empty_choices|raw }} {# this is it #}
{% endfor -%}
</div>
{%- endblock choice_widget_expanded -%}
{# or when using bootstrap_3.html.twig #}
{% block choice_widget_expanded -%}
{% if '-inline' in label_attr.class|default('') -%}
<div class="control-group">
{%- for child in form %}
{{- form_widget(child, {
parent_label_class: label_attr.class|default(''),
translation_domain: choice_translation_domain,
}) -}}
{% else %}
{{ empty_choices|raw }}
{% endfor -%}
</div>
{%- else -%}
<div {{ block('widget_container_attributes') }}>
{%- for child in form %}
{{- form_widget(child, {
parent_label_class: label_attr.class|default(''),
translation_domain: choice_translation_domain,
}) -}}
{% else %}
{{ empty_choices|raw }}
{% endfor -%}
</div>
{%- endif %}
{%- endblock choice_widget_expanded %} now you can use |
That is something similar i am using currently, but i thought it would be a good feature to be included in symfony itself |
Actually it might look like a bug when choice is On another hand it can't be solved globally without providing a way to customise the empty value IMO which means adding an option to an already over-optionnable ChoiceType and as a feature it could only be merged in 3.1. However the implementation I suggested above is about 10 lines of code to add in the core and is definitely more dev friendly so maybe it's worth it indeed. |
Thanks for reporting this issue! I think this can be solved quite easily in userland by overriding the {% use 'form_div_layout.html.twig' %}
{% block body %}
{% form_theme form _self %}
{# ... #}
{% endblock %}
{% block _my_field_id_widget %}
{%- if form.children is empty -%}
{# your HTML here #}
{%- else -%}
{# default rendering #}
{{- form_widget(form) -}}
{%- endif -%}
{% endblock %} Can you try that? |
I use a similar workaround, that works. but the point was to have something like this included in the component itself. |
@backbone87 I see. You could create a PR that renders the |
#17609 is just an example of implementation. To defend it, I would say it tries to solve this globally (expanded or not, multiple or not) with a dedicated view var, configurable through the option I find it handy to define a default message directly in the form type options. So @backbone87 feel free to open another PR to explore some other ideas, I've opened mine because I just think it sometimes simplifies the discussion about an implementation by allowing inline comments and showing an explicit diff. Cheers |
@HeahDude i agree with your approach, but ultimately the symfony deciders have to agree. maybe i would rename the option to |
It sounds like a good idea to use the same option name through different types which could also use by default the same It may be a way to be able to use it with compound custom form types when no fields show up, I'm thinking about dynamic forms. It might even be an approach to fix #17580 in the process since an empty compound form could actually be rendered if it has no children and the The option false by default would not render this block to keep BC, so we could have something like: {# for compound #}
{%- block form_rows -%}
{% for child in form %}
{{- form_row(child) -}}
+ {% else %}
+ {% if empty_form|default(false) %}{{ block('empty_row') }}{% endif %}
{% endfor %}
{%- endblock form_rows -%}
+ {%- block empty_row -%}
+ {{ empty_form|trans({}, translation_domain) }}
+ {%- endblock empty_row -%}
Then one would just have to override the {%- block empty_row -%}
<em>{{ empty_form|default('The field ' ~ full_name ~ ' is empty') }}</em>
{%- endblock empty_row -%} and set the option: $resolver->setDefault('empty_form', 'No fields yet but...'); What do you think ? |
sounds fine to me in general. |
@webmozart Forgive me as I just love to debate and I don't fully agree with you on this one.
Having another option would answer globally to the case any compound form type, including |
@HeahDude I realized the mistake in my comment already and deleted it. Thanks for pointing it out. |
The problem seems to be still there but the workaround is not working anymore. |
Just omit this option. It was only needed for the migration path from Symfony 2.6 to 3.0. |
Thank you for this suggestion. |
Friendly ping? Should this still be open? I will close if I don't hear anything. |
Simple use-case: categories and products
When editing the product an expanded (multiple) choice field of categories is displayed.
However when you create a product before you have created any category, there is simply the label/legend of the choice and some empty containers.
There are multiple solutions i came up with:
The text was updated successfully, but these errors were encountered: