如何避免将 attr 应用于我选择字段的所有选项?
How can I avoid applying attr to all options of my choice field?
在 Symfony 2.7 之前,choice
字段的 attr
值仅应用于字段本身,即呈现的 <select>
元素。我用它来将 类 应用到这个元素来设置它的样式。
在 Symfony 2.7 中,此行为已更改。现在,<select>
元素的所有 <option>
个子元素也获得相同的属性 (commit of the change),因此 类.
为便于说明,代码如下:
<?php echo $view['form']->widget($form['myField'], ['attr' => ['class' => "text ui-widget-content ui-corner-all"]]); ?>
那么这是 Symfony <=2.6 的输出:
<select class="text ui-widget-content ui-corner-all" name="myField">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
这是 Symfony >= 2.7 的输出:
<select class="text ui-widget-content ui-corner-all" name="myField">
<option value="1" class="text ui-widget-content ui-corner-all">Option 1</option>
<option value="2" class="text ui-widget-content ui-corner-all">Option 2</option>
</select>
我申请的类不适用于<option>
元素,因为它们为实际字段定义了边框等。请注意,这些是由 jQuery UI 定义的 类,因此我无法轻易更改它们的定义。
避免将这些 类 应用于 choice
字段的所有 <option>
元素同时仍将其应用于 <select>
元素的最简单方法是什么?
可能有更简单的解决方案,但您可能想看看 Form Themes。覆盖 choice_widget_options 的模板,使 类 不应用于选项标签。
{%- block choice_widget_options -%}
{% for group_label, choice in options %}
{%- if choice is iterable -%}
<optgroup label="{{ choice_translation_domain is sameas(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">
{% set options = choice %}
{{- block('choice_widget_options') -}}
</optgroup>
{%- else -%}
{% set attr = choice.attr %}
<option value="{{ choice.value }}" {# DELETE THIS PART: {{ block('attributes') }}#}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is sameas(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
感谢@user2268997 关于 choice_attr
的评论,我找到了相关博客 post New in Symfony 2.7: Choice form type refactorization ,其中详细介绍了(截至目前未记录)choice_attr
的使用选项。
似乎 Symfony 在渲染字段时将 choice_attr
中的属性与 attr
中的属性合并。这意味着我们需要覆盖 choice_attr
.
中的 class
属性
我尝试在我定义 attr
的代码旁边执行此操作,但没有成功。看来您需要在表单类型定义中执行此操作。这是添加 choice_attr
选项后我的表格的摘录:
namespace MyBundle\Form;
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('roles',
'entity',
[
'class' => 'MyBundle:Role',
'choice_label' => 'name',
'multiple' => true,
'choice_attr' => function () { return ["class" => ""]; }
]);
}
结果如我所愿。我可能还会将其重构为我自己的自定义表单类型,因此我不需要在我的包中重复它。
我现在决定创建一个具有上述所需行为的自定义 choice
类型,并在我的整个应用程序中使用该类型。
这是我选择的类型:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ChoiceNoOptAttrType extends ChoiceType {
public function configureOptions(OptionsResolver $resolver) {
parent::configureOptions($resolver);
$resolver->setDefault("choice_attr", function () { return ["class" => ""]; });
}
}
我不想重构我所有现有的表单来使用这个新类型,所以我选择用我的替换 Symfony 提供的选择类型。这可以通过修改 choice
表单类型的服务配置来实现。为此,我为我的包创建了一个编译器通道。
进一步阅读:Creating a Compiler Pass
namespace MyBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class MyCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition("form.type.choice");
$definition->setClass('MyBundle\Form\ChoiceNoOptAttrType');
}
}
现在剩下要做的就是在包中注册编译器传递。
进一步阅读: How to Work with Compiler Passes in Bundles
namespace MyBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use MyBundle\DependencyInjection\Compiler\MyCompilerPass;
class MyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new MyCompilerPass());
}
}
就是这样。现在我所有的 choice
字段都在使用我的自定义 class,这确保了 attr
中设置的 CSS class 不会传播到我的 <option>
元素。
在 Symfony 2.7 之前,choice
字段的 attr
值仅应用于字段本身,即呈现的 <select>
元素。我用它来将 类 应用到这个元素来设置它的样式。
在 Symfony 2.7 中,此行为已更改。现在,<select>
元素的所有 <option>
个子元素也获得相同的属性 (commit of the change),因此 类.
为便于说明,代码如下:
<?php echo $view['form']->widget($form['myField'], ['attr' => ['class' => "text ui-widget-content ui-corner-all"]]); ?>
那么这是 Symfony <=2.6 的输出:
<select class="text ui-widget-content ui-corner-all" name="myField">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
这是 Symfony >= 2.7 的输出:
<select class="text ui-widget-content ui-corner-all" name="myField">
<option value="1" class="text ui-widget-content ui-corner-all">Option 1</option>
<option value="2" class="text ui-widget-content ui-corner-all">Option 2</option>
</select>
我申请的类不适用于<option>
元素,因为它们为实际字段定义了边框等。请注意,这些是由 jQuery UI 定义的 类,因此我无法轻易更改它们的定义。
避免将这些 类 应用于 choice
字段的所有 <option>
元素同时仍将其应用于 <select>
元素的最简单方法是什么?
可能有更简单的解决方案,但您可能想看看 Form Themes。覆盖 choice_widget_options 的模板,使 类 不应用于选项标签。
{%- block choice_widget_options -%}
{% for group_label, choice in options %}
{%- if choice is iterable -%}
<optgroup label="{{ choice_translation_domain is sameas(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">
{% set options = choice %}
{{- block('choice_widget_options') -}}
</optgroup>
{%- else -%}
{% set attr = choice.attr %}
<option value="{{ choice.value }}" {# DELETE THIS PART: {{ block('attributes') }}#}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is sameas(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
感谢@user2268997 关于 choice_attr
的评论,我找到了相关博客 post New in Symfony 2.7: Choice form type refactorization ,其中详细介绍了(截至目前未记录)choice_attr
的使用选项。
似乎 Symfony 在渲染字段时将 choice_attr
中的属性与 attr
中的属性合并。这意味着我们需要覆盖 choice_attr
.
class
属性
我尝试在我定义 attr
的代码旁边执行此操作,但没有成功。看来您需要在表单类型定义中执行此操作。这是添加 choice_attr
选项后我的表格的摘录:
namespace MyBundle\Form;
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('roles',
'entity',
[
'class' => 'MyBundle:Role',
'choice_label' => 'name',
'multiple' => true,
'choice_attr' => function () { return ["class" => ""]; }
]);
}
结果如我所愿。我可能还会将其重构为我自己的自定义表单类型,因此我不需要在我的包中重复它。
我现在决定创建一个具有上述所需行为的自定义 choice
类型,并在我的整个应用程序中使用该类型。
这是我选择的类型:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ChoiceNoOptAttrType extends ChoiceType {
public function configureOptions(OptionsResolver $resolver) {
parent::configureOptions($resolver);
$resolver->setDefault("choice_attr", function () { return ["class" => ""]; });
}
}
我不想重构我所有现有的表单来使用这个新类型,所以我选择用我的替换 Symfony 提供的选择类型。这可以通过修改 choice
表单类型的服务配置来实现。为此,我为我的包创建了一个编译器通道。
进一步阅读:Creating a Compiler Pass
namespace MyBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class MyCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition("form.type.choice");
$definition->setClass('MyBundle\Form\ChoiceNoOptAttrType');
}
}
现在剩下要做的就是在包中注册编译器传递。
进一步阅读: How to Work with Compiler Passes in Bundles
namespace MyBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use MyBundle\DependencyInjection\Compiler\MyCompilerPass;
class MyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new MyCompilerPass());
}
}
就是这样。现在我所有的 choice
字段都在使用我的自定义 class,这确保了 attr
中设置的 CSS class 不会传播到我的 <option>
元素。