Symfony2 form widget container attributes - forms

I need set a class for widget container, but have no idea how Symfony passes attributes to "widget_container_attributes" block
Widget container template:
{% block form_widget %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{{ block('field_rows') }}
{{ form_rest(form) }}
</div>
{% endspaceless %}
{% endblock form_widget %}
Example result:
<div class="MY-CLASS">
<label class="required" for="page_title">Title</label>
<input type="text" value="Next subpage" maxlength="500" required="required" name="page[title]" id="page_title">
</div>
how can I do that?

try
{% extends 'form_div_layout.html.twig' %}
{% block field_rows %}
{% spaceless %}
{% for child in form %}
{{ form_row(child) }}
{% endfor %}
{% endspaceless %}
{% endblock field_rows %}
{% block field_row %}
{% spaceless %}
<div class="myclass">
{{ form_label(form, label|trans) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endspaceless %}
{% endblock field_row %}

Related

Extend bootstrap_3_layout.html.twig form theme

I am trying to customize the form layout in a symfony 3 project, by extending bootstrap_3_layout.html.twig form theme.
{# app/Resources/views/app/custom_bootstrap_metronic.html.twig #}
{% use "bootstrap_3_layout.html.twig" %}
{% block checkbox_widget -%}
{%- set parent_label_class =
parent_label_class|default(label_attr.class|default('')) -%}
{% if 'checkbox-inline' in parent_label_class %}
{{- form_label(form, null, { widget: parent() }) -}}
{% else -%}
<div class="checkbox">
{{- form_label(form, null, { widget: parent() }) -}}
</div>
{%- endif %}
{%- endblock checkbox_widget %}
and i added this in the configuration file:
{# app/config/config.yml #}
twig:
# form_themes: [bootstrap_3_layout.html.twig]
form_themes: [form/custom_bootstrap_metronic.html.twig]
what i want is to override the checkbox_widget so the rendered html will like:
<div class="form-group">
<div class="checkbox">
<label class="mt-checkbox">
<input type="checkbox" id="appbundle_accept"
name="appbundle[accept]" value="1">
Label
<span></span>
</label>
</div>
</div>
instead of:
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" id="appbundle_accept"
name="appbundle[accept]" value="1">
Label
</label>
</div>
</div>
I can't do that because the parent() function returns the checkbox_widget block from bootstrap_3_layout.html.twig and i need the checkbox_widget block from form_div_layout.html.twig
What i did is i copied the code from "bootstrap_3_layout.html.twig" in a file called "custom_bootstrap_metronic.html.twig" then i customized it.
{% block checkbox_widget -%}
{%- set parent_label_class = parent_label_class|default(label_attr.class|default('')) -%}
{% if 'checkbox-inline' in parent_label_class %}
{{- form_label(form, null, { widget: parent(), label_attr: {class: 'mt-checkbox'}}) -}}
{% else -%}
<div class="mt-checkbox-inline">
{{- form_label(form, null, { widget: parent(), label_attr: {class: 'mt-checkbox'}}) -}}
</div>
{%- endif %}
{%- endblock checkbox_widget %}
{% block checkbox_radio_label %}
{# Do not display the label if widget is not defined in order to prevent double label rendering #}
{% if widget is defined %}
{% if required %}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if parent_label_class is defined %}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' ' ~ parent_label_class)|trim}) %}
{% endif %}
{% if label is not same as(false) and label is empty %}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{- widget|raw }}
{{ label is not same as(false) ? (translation_domain is same as(false) ? label : label|trans({}, translation_domain)) -}}
<span></span> {# added this line #}
</label>
{% endif %}
{% endblock checkbox_radio_label %}

How to render a form error in red color?

Using Symfony3 && PhpStorm.2016.3.2 on Ubuntu 16.04
I have a form made in Twig, here is the section that interest me:
<div class="row">
<div class="input-field col s12 validate" id="icon_telephone" type="tel">
{{ form_errors(form) }}
{% if form.vars.errors|length %}
{ form_row(
form.authorPhone,
form.authorPhone.vars|merge({'attr': {'autofocus': null}})
)
}}
{% else %}
{{ form_row(form.authorPhone) }}
{% endif %}
</div>
</div>
I would like to "colorize" the error in Red as an example, without actually using customize form rendering of Symfony which force me to create a view etc..
So I wanted to know if there is a way to actually just turn the error red without industrializing the process.
Making something red is styling so you should be doing that via CSS.
Add a css file to your form template and you can customize the rendering of your form errors like so:
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<ul>
{% for error in errors %}
<li class="error-message">{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
And css
.error-message{
color: red;
}
Symfony doc article: https://symfony.com/doc/current/form/form_customization.html#customizing-error-output
Your final twig template would look like this:
<div class="row">
<div class="input-field col s12 validate" id="icon_telephone" type="tel">
{{ form_errors(form) }}
{% if form.vars.errors|length %}
{ form_row(
form.authorPhone,
form.authorPhone.vars|merge({'attr': {'autofocus': null}})
)
}}
{% else %}
{{ form_row(form.authorPhone) }}
{% endif %}
</div>
</div>
<link rel="stylesheet" href="{{ asset('bundles/mybundle/css/style.css') }}" />
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<ul>
{% for error in errors %}
<li class="error-message">{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
You override the form_errors block wich is what symfony will use when you call {{ form_errors(form) }}.
If you wan't the simplest solution just inspect you errors in the browser find the right selector and apply css without customizing the form rendering in twig.
For the stylesheet, create the file under Resources/public/css then execute app/console assets:install

Visual Studio Code removes wishful line breaks and indentation

Here is an example of HTML code with some Django template tags:
{% extends "blog/base.html" %}
{% block title %}
Title
{% endblock %}
{% block content %}
<h1>Header</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body }}
{% endfor %}
{% include "pagination.html" with page=posts %}
{% endblock %}
I want it to look like this. But VS Code reformats it to this view:
{% extends "blog/base.html" %} {% block title %} Title {% endblock %} {% block content %}
<h1>Header</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body }} {% endfor %} {% include "pagination.html" with page=posts %} {% endblock %}
What should I do to prevent this ugly reformatting?

Symfony2 (twig): pass array into form functions

I am trying to implement a form_function that can accept an array of forms.
FormExtension looks like this:
[...]
'form_controls_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
[...]
My field.html.twig would be this:
{% extends 'MopaBootstrapBundle:Form:fields.html.twig' %}
{# import "_self" as the form theme #}
{% form_theme form _self %}
{# make the form fragment customization #}
{% block form_controls_row %}
{% spaceless %}
<div class="controls controls-row">
{% for element in form %}
{{ form_row(element, _context) }}
{% endfor %}
<div>
{% endspaceless %}
{% endblock form_controls_row %}
And my form itself would look like that:
{% form_theme form 'MyBundle::fields.html.twig' %}
<div class="well">
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
{{ form_controls_row([form.firstName, form.lastName]) }}
{{ form_rest(form) }}
</form>
</div>
But everytime I pass in an array ([form.firstName, form.lastName]) into form_controls_row I get an exception.
Is there any way to allow arrays?
Or is there any better solution for my purpose?

symfony2 twig referencing base widget

I am trying to customize my symfony2 form choice_widget_expanded part, and trying to reference the base (standard) for the choice_widget_collapsed as per this instruction http://symfony.com/doc/current/cookbook/form/form_customization.html
But I get an error saying
Notice: Undefined index: choice_widget_collapsed in /var/www/beta/app/cache/dev/twig/ff/8a/9f46c90c543b16e78e981aeda67b.php line 19
Here is my twig code:
{% extends '::base.html.twig' %}
{% use 'form_div_layout.html.twig' with choice_widget_collapsed as base_choice_widget_collapsed %}
{% form_theme form _self %}
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
{{ block('choice_widget_expanded') }}
{% else %}
{{ block('base_choice_widget_collapsed') }}
{% endif %}
{% endspaceless %}
{% endblock choice_widget %}
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
<br />
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}
{% block contents %}
This works for me on a fresh composer install of sf 2.2.1. You should not need to clear cache for template changes to register in the dev environment, but it's worth a shot. It could also be that you need to stop and start (not restart) apache/php5-fpm if using an opcode cache.
Since you're only modifying choice_widget_expanded all you really need is:
test.html.twig
{% extends '::base.html.twig' %}
{% form_theme form _self %}
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
<br />
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}
{% block body %}
<form>
{{ form_row(form.choice) }}
</form>
{% endblock %}
testAction
/**
* #Template()
*/
public function testAction()
{
$builder = $this->createFormBuilder();
$builder->add('choice', 'choice', array(
'choices'=>array('one'=>'one', 'two'=>'two', 'three'=>'three'),
'expanded'=>true
));
$form = $builder->getForm();
return array('form'=>$form->createView());
}
Ah.. I am sure Dylans answer is correct, but for the symfony2 version I use (2.0.16) the template for that form looks a little different, the choice_widget_expanded doesn't have it's own block but it is all in this
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
<br /> {# <-------- Here's my addition to the template #}
{% 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 %}
I Should of course have pulled the code out of my own codebase instead of grabbing the latest version off of github, doh!