twig customizing form_row with form_theme - symfony

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 %}

Related

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 ;-)

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.

rendering forms and widget in Symfony2

I am developing a website and I would like to personalized how the forms are rendered.
My purpose is for each field I should achieve this structure
<div class="form-group">
<label for=":id">:LABEL</label>
<input type=":type" class="form-control" id=":id" />
</div>
In case of checkbox, the input must to appear first and without class atribute
The options for doing this are listed in Symfony Form Theming documentation.
In your form theme Twig file (normally app/Resources/views/form.html.twig) you should add something like this:
{% block form_row %}
{% spaceless %}
<div class="form-group">
{{ form_label(form) }}
{{ form_errors(form) }} {# Can remove this unless you want inline errors #}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control')|trim}) %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
The Ryan answer has needed to add one more line like this:
{% form_theme form _self %}
{% block form_row %}
{% spaceless %}
<div class="form-group">
{{ form_label(form) }}
{{ form_errors(form) }} {# Can remove this unless you want inline errors #}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control')|trim}) %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
as per symfony2 documentation How to customize Form Rendering the current template in which u want to make change , u will have to write the line
{% form_theme form _self %}
in the starting of any block overriding ..

How do I add a class to each expanded form widget in Symfony2?

Here are the Twig fields I'm trying to override: github
I have a list of checkbox that has been modified with this custom form theme:
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
<div class="checkbox_row">
{{ form_widget(child) }}
{{ form_label(child) }}
</div>
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}
I tried adding a class using {{ form_row(form.fieldName), {'attr':{'class':'myclass'}}) }}
But that only adds a class to the div#formName_fieldName. Next I tried adding a custom block with
{% block _formName_fieldName_widget %}
{% spaceless %}
<input type="checkbox" {{ block('widget_attributes') }} value="{{ value }}" class="myclass_{{ value }}" />
{% endspaceless %}
{% endblock choice_widget_expanded %}
Notice I also included the value as I want to have myclass_1, myclass_2 etc.
The problem with this is that the block receives an array so it should be like this
{% block _fb_post_facebook_pages_widget %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}
But then if I wanted to add the class to a specific checkbox, I would need to write something like this:
{% block _formName_fieldName_X_widget %}
{% spaceless %}
<input type="checkbox" {{ block('widget_attributes') }} value="{{ value }}" class="myclass_{{ value }}" />
{% endspaceless %}
{% endblock choice_widget_expanded %}
Where X would be a value that I have for the fieldName... And obviously the values could be anything so I can't just create block for all values from 1-1000000000000...
Any way to do this dynamically?
You would need to extend Twig, I believe. You can then specify the code in PHP and just bring in the conditions.
http://twig.sensiolabs.org/doc/advanced.html

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