How to apply class to form label? - symfony

I have this in a twig.
{{ form_errors(form) }}
{{ form_row(form.name, {'attr':{'class':'admin_finance_input'}}) }}
{{ form_row(form.amount, {'attr':{'class':'admin_finance_input'}}) }}
{{ form_rest(form) }}
Can anybody tell me how to set a class for form_label?

By checking the block_label from form_div_layout.html(https://github.com/symfony/symfony/blob/2.2/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig) you see this:
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
{% endif %}
so you can do this
{{ form_row(form.name, {'label_attr ':{'class':'admin_finance_input'}}) }}

In addition of Joao answer,
You are able to configure class attribute (and other html attributes if wanted) also when decomposing a form row :
<div class='form_row'>
<div class="error">{{ form_errors(form.name) }}</div>
{{ form_label(form.name, 'Choose a name:', 'attr': {'class': 'admin_finance_label'}) }}
{{ form_widget(form.name) }}
</div>

Related

Passing attr.class into the form theme in symfony 5

My form theme:
{% block form_row %}
<div class="form_row {% if errors|length > 0 %} is_error {% endif %} {{ attr.class }}" {% if attr|length > 0 %} {% for key, value in attr %} {{key}}="{{value}}" {% endfor %} {% endif %}>
{% if block_prefixes.1 != "checkbox" %}
{{ form_label(form)|raw }}
{% endif %}
{% if icon != null and block_prefixes.1 != "checkbox" %}
<div class="input__icon-container {% if block_prefixes.2 == "password" %}input__password-container{% endif %}">
<div class="icon">
{{ source('#public_path' ~ asset('build/images/icons/' ~ icon|replace({"icon-":""}) ~ '.svg')) }}
</div>
{% if block_prefixes.2 == "password" %}
<span class="password-reveal">Show</span>
{% endif %}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
</div>
{{ form_errors(form) }}
{% else %}
{% if block_prefixes.2 == "password" %}
<div class="input__password-container">
<span class="password-reveal">Show</span>
{% endif %}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
{% if block_prefixes.2 == "password" %}
</div>
{% endif %}
{{ form_errors(form) }}
{% endif %}
</div>
{% endblock %}
{% block radio_widget %}
<div class="label">{{ label|raw }} {% if help != null %} <span class="help">{{help}}</span> {% endif %}</div>
{% for choice in choices %}
<div class='input__choice-container'>
<label class="is_regular"> <input type="radio" name="{{ full_name}}" {% if required == "true" %} required="required" {% endif %} value="{{ choice.value }}"><span class="radio"></span> <span>{{ choice.label }}</span> </label>
</div>
{% endfor %}
{% endblock %}
{% block checkbox_widget %}
<div class="custom-checkbox custom-control">
<input type="checkbox" class="custom-control-input" id="{{id}}" name="{{ full_name}}">
<label class="custom-control-label" for="{{id}}">{{label|raw}}</label>
</div>
{% endblock %}
The error I got:
Key "class" does not exist as the array is empty.
But that's not accurate because this is my form output for this form row:
{{ form_row(registrationForm.displayname, {
attr : { "class" : "mb-1", "data-test" : "tests"}
})}}
So the question is here, how do I output the class content in the appropriate manner? Clearly I'm doing it wrong.
It is because your template doesnt print class literally
Understand the structure of forms here Form Customization
You will need to inject attribute print logic just like one of the built-in templates found( bootstrap 4 example) in Form Themes
{% block form_row -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- endif -%}
<div{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group' ~ ((not compound or force_error|default(false)) and not valid ? ' has-error'))|trim})} %}
{{ block('attributes') }}
{% endwith %}>
{{- form_label(form) }} {# -#}
{{ form_widget(form, widget_attr) }} {# -#}
{{- form_help(form) -}}
{{ form_errors(form) }} {# -#}
</div> {# -#}
{%- endblock form_row %}
If you don't want to do it over, extend built in form widgets which has the printing logic.
Or simply work out on your block to print these passed attributes.

Symfony form builder - how to put form title in h2 selector?

I want my form title to be displayed in h2 selector. I did something like that but it throws me an error "exception: "An exception has been thrown during the rendering of a template ("Notice: Undefined offset: -1").""
// how should I change THIS part? To change only the main form title/label?
// I made it work somehow but then it changes all labels... Is there some
// selector which allows to style MAIN title of the form?
{% block form_label %}
{% spaceless %}
<h2>{{ form_label(form) }}</h2>
{% endspaceless %}
{% endblock form_label %}
I've heard that I shouldn't put it in my project file in h2 selector just in form template. It's cleaner and even though documentation doesn't forbide that I was encouraged to do it another way and that's how I want to try it.
{% form_theme form 'Forms/base_form.html.twig' %}
{{ form_start(form) }}
{{ form_label(form, 'Project title', { 'label_attr': {'class': 'main-form-label'} }) }}
// so as I shouldn't put all that line in <h2> can I somehow do it in template between {% block form_label %} ?
{{ form_row(form.title, {'label': 'My title'}) }}
{{ form_row(form.isComplete, {'label': 'Dropdown'}) }}
{{ form_row(form.comment, {'label': 'Comment'}) }}
{{ form_row(form.submit, {'label': 'Submit'}) }}
{{ form_end(form) }}
Also... Whats the difference/what should I use - {% block form_label %} or {%- block form_label -%}
My whole template:
{% block form_label %}
{% spaceless %}
<h2>{{ form_label(form) }}</h2>
{% endspaceless %}
{% endblock form_label %}
{% block form_row %}
{% spaceless %}
{{ form_widget(form) }}
{{ form_errors(form) }}
{% endspaceless %}
{% endblock form_row %}
{% block submit_row %}
{% spaceless %}
<div class="col-12">
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock submit_row %}
{% block text_widget %}
{% spaceless %}
<div class="col-12">
<div>
{{ form_label(form) }}
</div>
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock text_widget %}
{% block choice_widget %}
{% spaceless %}
<span>
{{ form_label(form) }}
{% if expanded %}
{{ block('choice_widget_expanded') }}
{% else %}
{{ block('choice_widget_collapsed') }}
{% endif %}
{{ form_errors(form) }}
</span>
{% endspaceless %}
{% endblock choice_widget %}
In case you get stuck somewhere ;)
We use to do it this way (when we want custom rendering).
First, we extend the FormType :
namespace App\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FormTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return FormType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('main_title', false);
$resolver->setAllowedTypes('main_title', 'boolean');
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['main_title'] = $options['main_title'];
}
}
Think to register you extension in Symfony !
Then you can use it in your form builder this way :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'myField',
TextType::class,
array(
'main_title' => true
));
}
Finally, in your template :
{% block form_row -%}
{% spaceless %}
{% if main_title %}
<h2>{{ form_label(form) }}</h2>
{% else %}
{{ form_label(form) }}
{{ form_widget(form) }}
{% endif %}
{% endspaceless %}
{%- endblock form_row %}
Feel free to override that block with your needs ;-)

twig customizing form_row with form_theme

I want to remove 'div' from form_row block using form_theme like this:
{% form_theme feedback_form _self %}
{% block form_row %}
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{% endblock %}
{{ form_start(feedback_form) }}
{{ form_row(feedback_form.name) }}
{{ form_row(feedback_form.email) }}
{{ form_row(feedback_form.subject) }}
<button type="submit">Send</button>
{{ form_end(feedback_form) }}
just like it is said in Doc https://symfony.com/doc/2.8/form/form_customization.html#customizing-the-form-row
The trouble is that twig tries to render the {% block form_row %} right in that place of template, where it is, and the result is
Variable "form" does not exist.
because I don't have variable 'form' in this template.
The template is rendered by separate action in the footer of page, and it doesn't extend anything.
Ok, I found the solution while was writing the question.
Putting the code of form_row block to the separate file solves the problem.
{# feedback_form.html.twig #}
{% form_theme feedback_form 'fields.html.twig' %}
{{ form_start(feedback_form) }}
{{ form_row(feedback_form.name) }}
{{ form_row(feedback_form.email) }}
{{ form_row(feedback_form.subject) }}
<button type="submit">Send</button>
{{ form_end(feedback_form) }}
{# fields.html.twig #}
{% block form_row %}
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{% endblock %}
Extending another template helps too.
{# base.html.twig #}
{% block content %}
{% endblock %}
{# feedback_form.html.twig #}
{% extends 'base.html.twig' %}
{% form_theme feedback_form _self %}
{% block form_row %}
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{% endblock %}
{% block content %}
{{ form_start(feedback_form) }}
{{ form_row(feedback_form.name) }}
{{ form_row(feedback_form.email) }}
{{ form_row(feedback_form.subject) }}
<button type="submit">Send</button>
{{ form_end(feedback_form) }}
{% endblock %}

Symfony 2 Form Theming Each Row?

I have been over the docs many times, but I can not seem to find a simple answer to my question. In my form, how do I apply a themed block to each row of my form, so that the right classes can be applied.
To explain, I currently have this in my twig template:
{% form_theme form 'XXBundle:Themes/floatRows.html.twig' %}
{{ form_start(form, {'attr': {'id': 'MyIDForm'}}) }}
{{ form_errors(form) }}
{{ form_row(form.row1) }}
{{ form_row(form.row2) }}
{{ form_row(form.row2) }}
{{ form_end(form) }}
In my theme file:
{% block form_row %}
<div class="ftLeft">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
However what I am trying to do is this,
In my theme file I want,
{% block FloatLeft %}
<div class="ftLeft">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
{% block FloatRight %}
<div class="ftRight">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
Then to be able to apply each of these blocks to each row in turn (or wherever else I want them):
{{ form_start(form, {'attr': {'id': 'MyIDForm'}}) }}
{{ form_errors(form) }}
{{ form_row(form.row1) }} <-Block FloatLeft
{{ form_row(form.row2) }} <-Block FloatRight
{{ form_row(form.row2) }} <-No Block, no float class!
{{ form_end(form) }}
All help all ways welcome.
Thanks.
I used to have the same problem. I just solved it by extending twig with new simple functions. If you don't know how to go to this topic
Your function and your template must have the same name.

Defining custom twig form block for errors rendering

I'm trying to define a specific new block for form field errors rendering, keeping form_errors unchanged for common errors rendering.
# Twig Configuration
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
form:
resources:
- 'ApplicationMyBundle:Main:form/customFormTheme.html.twig'
In customFormTheme.html.twig I overwrite a few blocks copied from form_div_layout.html.twig plus I added the folloowing new one.
{% block field_errors %}{% spaceless %}
{% if errors|length > 0 %}
<ul class="errors">
{% for error in errors %}
{% if error.messageTemplate|length %}
<li class="error">{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% endspaceless %}{% endblock %}
Then I expect to be able to use this block in my views like this :
<div>
{{ form_label(form.message, 'message.label'|trans({},'contact')|raw ) }}
{{ form_widget(form.message, {attr: {maxlength:1000, size:1000, rows:8}}) }}
{{ field_errors(form.message) }}
</div>
but I receive the following error :
The function "field_errors" does not exist. Did you mean "form_errors"
I also tried by naming my block text_errors or textarea_errors mentioned here but I haven't been luckier.
Any idea ?
Actually it works by defining the block text_errors or textarea_errors only and still use {{ form_errors(field.name) }} in your template. If a block named after the type of your field exists (according to form field types) it will be used instead of form_errors.
!! But you can't use directly {{ text_errors(field.name) }} in your twig template !!
The same way you can have a custom row for a specific type like this
{% block textarea_row %}{% spaceless %}
<div class="textarea l-field {{ (form_errors(form)?'error':'') }}">
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endspaceless %}{% endblock textarea_row %}
and use it in your template as follow :
{# message has textarea field type #}
{{ form_row(form.message, {
label: 'message.label'|trans({},'contact')|raw ,
attr: {maxlength:1000, size:1000, rows:8}})
}}
You can also pass many custom parameters by using the object attr{}
{% block form_row %}
{% spaceless %}
<div class="form-field {{ (form_errors(form)?'error':'') }}">
{{ form_label(form) }}
{{ form_widget(form) }}
{{ dump(attr) }}
{% if attr.help is defined and not attr.help == '' %}<p class="form-help">{{ attr.help }}</p>{% endif %}
{{ form_errors(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
and use it like this
{{ form_row(form.message, {
label: 'message.label'|trans({},'contact')|raw ,
attr: {
maxlength:1000, size:1000, rows:8,
help: 'password.help'|trans({})|raw
}
})
}}

Resources