【问题标题】:Symfony twig how to add class to a form rowSymfony twig 如何将类添加到表单行
【发布时间】:2014-05-25 13:00:03
【问题描述】:

我正在使用 Twig 在 Symfony 2.3 中构建一个项目。我想向表单行块添加一个类。我正在使用一个表单主题文件,其中包含:

{% block form_row %}
    <div class="form-row">
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock %}

现在我想在我的一些表单行中添加一个额外的类form-row-split。我不知道如何正确地做到这一点。我几乎可以使用的方式是:

{% block form_row %}
    {% set attr = attr|merge({'class': 'form-row' ~ (attr.class is defined ? ' ' ~ attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
    <div {{ block('widget_container_attributes') }}>
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock %}

(注意,我也将error 类逻辑留在了那里,因为它需要保留)。 然后在表单生成器中:

$builder
        ->add('first_name', 'text', array(
            'attr' => array(
                'class' => 'form-row-split'
            )
        ));

这几乎可以工作,但它在任何地方都添加了这个类,并将小部件 id 添加到行中!

<div id="myform_first_name" class="form-row form-row-split">
    <label for="myform_first_name">First name</label>
    <input id="myform_first_name" class="form-row-split" type="text" name="myform[first_name]">
</div>

我能想到一些潜在的解决方案,但没有一个是漂亮或直接的。肯定有一种简单的方法可以做到这一点?

【问题讨论】:

  • 为什么不在您的 css 文件中实现 div.form-row-splitlabel.form-row-splitinput.form-row-split 而不是简单的 form-row-split,而不是在表单生成中找到一个 hack?

标签: symfony twig symfony-forms


【解决方案1】:

我所做的更简单(虽然可能不太干净?)。

通过字段的“数据”属性传递表单行的类:

// template.html.twig

{{ form_start(form) }}
    {{ form_row(form.field, {'attr': {'data-row-class': 'my-row-class'} }) }}
{{ form_end(form) }}

然后在表单主题模板中这样处理:

// form-theme.html.twig

{% block form_row -%}
    {% set row_class = attr['data-row-class'] | default('') %}
    <div class="{{ row_class }}">
        {{- form_label(form) -}}
        {{- form_widget(form) -}}
        {{- form_errors(form) -}}
    </div>
{%- endblock form_row %}

这给出了这个:

<form name="formName" method="post">
    <div class="my-row-class">
        <label for="formName_field">Field label</label>
        <input type="text" id="formName_field" name="formName[field]" data-row-class="my-row-class">
    </div>
</form>

【讨论】:

    【解决方案2】:

    以下是@loplateral 的答案克隆,但变化反映了最新的 Symfony 结构变化(v. 2.7+):


    这个问题实际上有一个相当简单的解决方案。我只需要一个表单类型扩展来扩展基本表单类型以允许额外的可用选项:http://symfony.com/doc/master/form/create_form_type_extension.html

    按照文档中的示例,我创建了一个新的表单类型扩展:

    // src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php
    
    namespace Acme\FrontendBundle\Form\Extension;
    
    use Symfony\Component\Form\AbstractTypeExtension;
    use Symfony\Component\Form\FormInterface;
    use Symfony\Component\Form\FormView;
    use Symfony\Component\Form\Extension\Core\Type\FormType;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    /**
     * Class FormTypeExtension
     * @package Acme\FrontendBundle\Form\Extension
     */
    class FormTypeExtension extends AbstractTypeExtension
    {
        /**
         * Extends the form type which all other types extend
         *
         * @return string The name of the type being extended
         */
        public function getExtendedType()
        {
            return FormType::class;
        }
    
        /**
         * Add the extra row_attr option
         *
         * @param OptionsResolver $resolver
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'row_attr' => []
            ));
        }
    
        /**
         * Pass the set row_attr options to the view
         *
         * @param FormView $view
         * @param FormInterface $form
         * @param array $options
         */
        public function buildView(FormView $view, FormInterface $form, array $options)
        {
            $view->vars['row_attr'] = $options['row_attr'];
        }
    }
    

    然后我在我的包中注册了该服务...

    <!-- Form row attributes form extension -->
    <service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
        <tag name="form.type_extension" alias="form" extended_type="Symfony\Component\Form\Extension\Core\Type\FormType" />
    </service>
    

    由于每个小部件都扩展了基本表单类型,因此我可以在任何字段上传递这个新的row_attr 选项,例如:

    $builder
        ->add('first_name', TextType:class, [
            'row_attr' => [
                'class' => 'form-row-split'
            ]
        ]);
    

    然后树枝覆盖以使用新的row_attr 选项:

    {% block form_row %}
        <div {{ block('form_row_attributes') }}>
            {{ form_label(form) }}
            {{ form_widget(form) }}
            {{ form_errors(form) }}
        </div>
    {% endblock form_row %}
    
    {% block form_row_attributes %}
        {% spaceless %}
            {% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
        {% endspaceless %}
    {% endblock form_row_attributes %}
    

    它已经完成了!

    (为了完整起见,我的完整树枝覆盖仍然合并到 form-rowerror 类中,如下所示:

    {% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
    

    .. 但这对于回答我自己的问题并不是真正必要的:P)

    【讨论】:

      【解决方案3】:

      这个问题实际上有一个相当简单的解决方案。我只需要一个表单类型扩展来扩展基本表单类型以允许额外的可用选项:http://symfony.com/doc/2.3/cookbook/form/create_form_type_extension.html

      按照文档中的示例,我创建了一个新的表单类型扩展:

      // src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php
      
      namespace Acme\FrontendBundle\Form\Extension;
      
      use Symfony\Component\Form\AbstractTypeExtension;
      use Symfony\Component\Form\FormInterface;
      use Symfony\Component\Form\FormView;
      use Symfony\Component\OptionsResolver\OptionsResolverInterface;
      
      /**
       * Class FormTypeExtension
       * @package Acme\FrontendBundle\Form\Extension
       */
      class FormTypeExtension extends AbstractTypeExtension
      {
          /**
           * Extends the form type which all other types extend
           *
           * @return string The name of the type being extended
           */
          public function getExtendedType()
          {
              return 'form';
          }
      
          /**
           * Add the extra row_attr option
           *
           * @param OptionsResolverInterface $resolver
           */
          public function setDefaultOptions(OptionsResolverInterface $resolver)
          {
              $resolver->setDefaults(array(
                  'row_attr' => array()
              ));
          }
      
          /**
           * Pass the set row_attr options to the view
           *
           * @param FormView $view
           * @param FormInterface $form
           * @param array $options
           */
          public function buildView(FormView $view, FormInterface $form, array $options)
          {
              $view->vars['row_attr'] = $options['row_attr'];
          }
      }
      

      然后我在我的包中注册了该服务...

      <!-- Form row attributes form extension -->
      <service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
          <tag name="form.type_extension" alias="form" />
      </service>
      

      由于每个小部件都扩展了基本表单类型,因此我可以在任何字段上传递这个新的row_attr 选项,例如:

      $builder
          ->add('first_name', 'text', array(
              'row_attr' => array(
                  'class' => 'form-row-split'
              )
          ));
      

      然后树枝覆盖以使用新的row_attr 选项:

      {% block form_row %}
          <div {{ block('form_row_attributes') }}>
              {{ form_label(form) }}
              {{ form_widget(form) }}
              {{ form_errors(form) }}
          </div>
      {% endblock form_row %}
      
      {% block form_row_attributes %}
          {% spaceless %}
              {% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
          {% endspaceless %}
      {% endblock form_row_attributes %}
      

      它已经完成了!

      (为了完整起见,我的完整树枝覆盖仍然合并到 form-rowerror 类中,如下所示:

      {% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
      

      .. 但这对于回答我自己的问题并不是真正必要的:P)

      【讨论】:

      【解决方案4】:

      Docs 说:你总是可以将 attr 传递给渲染元素:

      {{ form_start(form, {'attr': {'class': 'your-class'}} ) }}
          {{ form_label(form, {'attr': {'class': 'your-class'}}) }}
          {{ form_widget(form, {'attr': {'class': 'your-class'}}) }}
          {{ form_errors(form, {'attr': {'class': 'your-class'}}) }}
      {{ form_end(form) }}
      

      【讨论】:

      • 这仅允许您将attr 传递给表单、标签、小部件、错误,而不是行。实际上,如果您查看原始主题文件(form_div_layout.html.twig),您可以看到在form_row 块中,周围的&lt;div&gt; 将永远不会注入任何传递的变量......因此我的问题是如何做到这一点。不过谢谢你的建议。
      • @loplateral,你是对的,那么只有一个选项 - 覆盖 form_row,以满足您在模板中的需要。
      • 是的,我有 form_row 覆盖,但我需要一半的行使用一个版本,另一半使用另一个版本和额外的 form-row-split 类。除了他们都使用相同的 form_row 覆盖块 - 所以我需要能够以某种方式将一些东西传递到这个覆盖块中......
      猜你喜欢
      • 1970-01-01
      • 2015-08-08
      • 2014-11-01
      • 1970-01-01
      • 2021-04-27
      • 2021-08-09
      • 2016-11-01
      • 2016-10-27
      • 1970-01-01
      相关资源
      最近更新 更多