【问题标题】:Is there a way to wrap label around input in symfony2?有没有办法在 symfony2 中围绕输入包装标签?
【发布时间】:2012-05-30 11:39:46
【问题描述】:

关于symfony2表单组件及其模板的问题:

我有一堆复选框要设置样式(一个表单行中大约有 10 个)。通常我以这种方式使用<label> 标签:<label><input/> some text</label> 但我找不到在表单模板(form_div_layout.html.twig)中更改它的方法。我什至找不到将任何标签包裹在输入小部件及其标签周围的方法,我总是以这样的标记结束:<input/> <some_tag><label>some text</label></some_tag><some_tag><input/></some_tag> <label>some text</label>,至少可以说这不是很有用......

谷歌了很多,但找不到答案。

【问题讨论】:

    标签: forms symfony label twig


    【解决方案1】:

    Whistlegreg 是正确的,您需要覆盖 twig 表单模板。但是,您不需要删除 {% block generic_label %} 块。如果您需要有关如何覆盖模板的帮助,请参阅他的回答。

    为了用标签包装复选框输入标签,第一步是覆盖 {% block choice_widget %} 块并从打印出单独标签的 {% if expanded %} 部分中删除 {{ form_label(child) }} 行。

    {% block choice_widget %}
    {% spaceless %}
        {% if expanded %}
            <div {{ block('widget_container_attributes') }}>
            {% for child in form %}
                {{ form_widget(child) }}
            {#  {{ form_label(child) }} <--------------------- remove this line #}  
            {% endfor %}
            </div>
        {% else %}
        <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
            {% if empty_value is not none %}
                <option value="">{{ empty_value|trans }}</option>
            {% endif %}
            {% if preferred_choices|length > 0 %}
                {% set options = preferred_choices %}
                {{ block('widget_choice_options') }}
                {% if choices|length > 0 and separator is not none %}
                    <option disabled="disabled">{{ separator }}</option>
                {% endif %}
            {% endif %}
            {% set options = choices %}
            {{ block('widget_choice_options') }}
        </select>
        {% endif %}
    {% endspaceless %}
    {% endblock choice_widget %}
    

    现在您只需要处理打印{% block checkbox_widget %} 块中的标签。

    {% block checkbox_widget %}
    {% spaceless %}
        <label  for="{{ id }}"><input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
    {% endspaceless %}
    {% endblock checkbox_widget %}
    

    您需要对{% block radio_widget %} 执行相同操作,因为它现在不会有标签。

    {% block radio_widget %}
    {% spaceless %}
        <label  for="{{ id }}"><input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
    {% endspaceless %}
    {% endblock radio_widget %}
    

    【讨论】:

    • @ilanco 在 2.0.15 中对我来说工作正常:&lt;div class="control-group"&gt; &lt;label class="control-label"&gt;Position type&lt;/label&gt; &lt;div class="controls expanded-choice-group"&gt; &lt;label for="profile_edit_position_type_full-time" class="checkbox"&gt; &lt;input type="checkbox" id="profile_edit_position_type_full-time" name="profile_edit[position_type][full-time]" value="full-time" /&gt; Full-time &lt;/label&gt; ...snip for brevity... &lt;span class="help-inline"&gt;&lt;/span&gt; &lt;/div&gt; &lt;/div&gt;
    【解决方案2】:

    我认为这就是您要寻找的: http://symfony.com/doc/current/book/templating.html#overriding-bundle-templates

    您可以通过在 app/resources 文件夹中创建另一个同名文件来覆盖任何默认的树枝模板。

    在您想要覆盖 form_div_layout.html.twig 模板的情况下,将其从捆绑包复制到 app/Resources/TwigBundle/views/Form/form_div_layout.html.twig,自定义掉,symfony 将使用它而不是默认。

    编辑:覆盖模板后,您可以修改 {% block checkbox_widget %} 以使用 twig vars 使用标签标签包装输入

    <label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>
      {{label|trans }} 
      <input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} /> 
    </label> 
    

    您还需要删除“generic_label”定义,这意味着每个其他块都需要修改。

    【讨论】:

    • 伙计们,我知道如何自定义和覆盖布局,只是我找不到将&lt;label&gt; 标签包裹在输入周围的方法。而且我严重怀疑它是否可能,因为标签的树枝模板看起来像这样:{{ form_label(form.field_name) }} 并且显然被呈现为一个元素。不是开始和结束标签。现在我只是在使用这个 jQ:$('input+label').each(function(){$(this).prepend($(this).prev());}); 但它看起来像一个临时修复......
    • 嗯,有什么原因不能在输入之前或之后放置标签吗?我知道这不是您要问的,但是标签内的输入会破坏 w3 规范,并且可能会导致您出现问题。来自 W3:“标签本身可能位于关联控件之前或之后。” w3.org/TR/html401/interact/forms.html#edef-LABEL
    • 原因是样式更容易 - 只需将标签设置为 50% 宽度,显示内联块,固定高度,并且您已经整理好输入,而使用一组内联元素,它就变成了混乱。至于 W3C - 上次我检查输入可以放在标签内,只有没有 for 属性的标签可能不符合 WCAG:w3schools.com/html5/tag_label.asp
    • 很公平 - 我不是树枝大师,但我仍然认为您可以在 form_div_layout.html.twig 文件中实现您想要的,您只需要进行一些重大的重组。您可以修改 {% block checkbox_widget %} 以使用 twig vars 用标签标签包装输入吗?
    • 它确实有效。有点:-)唯一的问题是我需要删除'generic_label'定义,所以每个其他块都需要修改。编辑您的答案,我会接受,非常感谢。
    【解决方案3】:

    可以为特定表单小部件类型的行定义块,例如{% block checkbox_row %}。我在这里发现了这个:http://forum.symfony-project.org/viewtopic.php?f=23&t=57986#p153546

    然后将标签包裹在小部件周围以用于复选框的所有内容如下:

    {% block checkbox_row %}
    {% spaceless %}
        <div>
            {% if not compound %}
                {% set label_attr = label_attr|merge({'for': id}) %}
            {% endif %}
            {% if required %}
                {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
            {% endif %}
            <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}
            {{ form_widget(form) }}
            {% if label is empty %}
                {% set label = name|humanize %}
            {% endif %}
            </label>
            {{ form_errors(form) }}
        </div>
    {% endspaceless %}
    {% endblock checkbox_row %}
    

    标签代码已从{% block form_label %} 复制并粘贴。当我使用 Zurb 的 Foundation 框架时,我已将表单错误放在小部件下方。

    单选按钮的代码更复杂,因为{% block radio_row %} 似乎不存在,所以你必须接受 Whistlegreg 的建议并编辑 {% block choice_widget %} 块,在 Symfony 2.1 中实际上现在是 {% block choice_widget_expanded %}。这是我的代码:

    {% block choice_widget_expanded %}
    {% spaceless %}
        <div {{ block('widget_container_attributes') }}>
        {% for child in form %}
            {% set child_label = child.get('label') %}
            {% if child_label is not sameas(false) %}
                {% set child_id = child.get('id') %}
                {% set child_compound = child.get('compound') %}
                {% set child_required = child.get('required') %}
                {% set child_label_attr = child.get('label_attr') %}
                {% if not child_compound %}
                    {% set child_label_attr = child_label_attr|merge({'for': child_id}) %}
                {% endif %}
                {% if child_required %}
                    {% set child_label_attr = child_label_attr|merge({'class': (child_label_attr.class|default('') ~ ' required')|trim}) %}
                {% endif %}
                <label{% for attrname, attrvalue in child_label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
            {% endif %}
            {{ form_widget(child) }}
            {% if child_label is not sameas(false) %}
                {% if child_label is empty %}
                    {% set child_label = name|humanize %}
                {% endif %}
                {{ child_label|trans({}, translation_domain) }}
                </label>
            {% endif %}
        {% endfor %}
        </div>
    {% endspaceless %}
    {% endblock choice_widget_expanded %}
    

    在 Symfony 2.1.9 DEV 中测试和工作。

    【讨论】:

    • 对象“Symfony\Component\Form\FormView”的方法“get”不存在
    【解决方案4】:

    我认为您可以通过更改 form_row 块来做到这一点。

    试试这样的:

    {% block form_row %}
    {% spaceless %}
        <label>
            {{ form_widget(form) }}
        </label>
    {% endspaceless %}
    {% endblock form_row %}
    

    但请注意,这绝对不是一个非常灵活的解决方案...
    您可能应该仅将其用于特定类型,而不是全部使用。
    无论如何,您必须使用form_row 才能使其正常工作。

    【讨论】:

    • 它不起作用,因为所有输入都在一行中。整个结构或多或少看起来像这样:一些表单行,前两行带有一组复选框,其他行带有一个文本输入或内部选择。所以包装一行没有任何帮助。对于这个特定的表单,我想我会继续使用 jQ,我计划在它之上构建一些自定义 UI,无论如何(jquery.ui 滑块等)。
    • 您只能对给定的类型使用此技巧。例如通过定义choice_row 块来选择。您也可以通过定义 _your_type_name_row 块仅对一种给定类型执行此操作。
    猜你喜欢
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多