Symfony2中的自定义表单字段,继承了不需要的属性

时间:2012-03-26 07:34:01

标签: symfony symfony-forms

我在理解Symfony2 自定义表单字段类型的工作方式时遇到了一些麻烦。我需要根据传递给data-*的数据创建一个包含一些自定义属性(HTML5 MyType)的新类型。

问题,在将MyType添加到主表单后,其标签会继承data-*属性。

// Add MyType to the main form

$builder->add('somename', new MyType(), array('label' => 'my label'));

这是我的自定义类型:

class MyType extends AbstractType
{

    public function getDefaultOptions(array $options)
    {
       $source = isset($option['source']) ? json_encode($option['source']) : '';

        return array(
            'attr' => array(
                'data-source' => $source
            )
        );
    }

    public function getName() { return 'mytype'; }

    public function getParent(array $options) { return 'text'; }

}

2 个答案:

答案 0 :(得分:1)

所以基本问题是标签会获取窗口小部件上的所有属性。我真的不明白为什么他们这样设计它,但如果你看一下:

{# Symfony/Bridge/Twig/Resources/Form/form_div_layout.html.twig #}
{% block generic_label %}
{% spaceless %}
    {% if required %}
        {% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
    {% endif %}
    <label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor%}>{{ label|trans }}</label>
{% endspaceless %}
{% endblock %}

您可以看到generic_label(默认情况下调用)会转储每个属性。

我用以下方式覆盖了默认值:

{% block generic_label %}
{% spaceless %}
    {% if required %}
        {% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
    {% endif %}
    <label {{ block('label_attributes') }}>{{ label|trans }}</label>
{% endspaceless %}
{% endblock %}

{% block label_attributes %}
{% spaceless %}
    {% for attrname,attrvalue in attr %}{% if (attrname == 'for' or attrname == 'class') %} {{attrname}}="{{attrvalue}}"{% endif %}{% endfor %}
{% endspaceless %}
{% endblock %}

我的label_attributes块只显示for和class属性,这是我到目前为止所需要的。同样,默认的实现是令人困惑的,我可能错过了一些明显的东西,但覆盖似乎工作正常。使用form_theme引入新的表单文件:

{% form_theme form 'ZaysoCoreBundle:Layout:fields.html.twig' %}

答案 1 :(得分:1)

编辑:据我所知,传递array('attr' => array('myattr1' => 'value1'))作为构建器的选项旨在作为构建器的常用属性以及所有其子元素。这就是为什么,例如,在表单级别传递array('required' => false)将禁用该表单中每个字段的HTML5内置客户端验证。

(一直在寻找更好的解决方案)我会发布自己的方式,受到blog post的启发:自定义表单字段查看属性 Twig block 以创建新属性。

class TypeheadType extends AbstractType
{

    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->setAttribute('mode',  $options['mode'])
            ->setAttribute('items', $options['items']);

    }

    public function buildView(FormView $view, FormInterface $form)
    {

        $view
            ->set('mode',  $form->getAttribute('mode'))
            ->set('items', $form->getAttribute('items'));
    }

    public function getDefaultOptions(array $options)
    {

        return array(
            'mode'  => 'single',
            'items' => 10
        );
    }

    public function getName() { return 'typehead'; }

    public function getParent(array $options) { return 'field'; }

}

新表单类型应该注册为服务,别名应该与getName()返回的内容相匹配(这是强制性的吗?dunno ...):

form.type.typehead:
  class: Acme\HelloBundle\Form\Type\TypeheadType
  tags:
    - { name: form.type, alias: typehead }

新的字段创建(其他地方):

$builder->add('myfield', 'typehead', array('items' => 15));

在Twig表单主题窗口小部件块(名称模式为as getName() . '_widget)中,您可以使用TypeheadType中设置的视图属性:

{% block typehead_widget %}
{% spaceless %}
    <input type="text" {{ block('widget_attributes') }} 
        {% if value is not empty %}value="{{ value }}" {% endif %}
        data-items="{{ items }}" data-mode="{{ mode }}" />
{% endspaceless %}
{% endblock typehead_widget %}

最后:

{{ form_row(form.myfield) }}