Symfony2 choice_widget print only the label without markup? - forms

Here is choice_widget template from Symfony2. I need to print the label text itself without markup, that is without calling form_label template but simply echoing the text.
The line to be sostituted is {{ form_label(child) }}. I've tried child.label but it's not working (there is no property label...). Also tried label but it prints the label of the whole widget, not the label of the current child element.
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }} {# here! #}
{% endfor %}
</div>
{% else %}
{# print <select> element #}
{% endif %}
{% endspaceless %}
{% endblock choice_widget %}

Form fields' attributes are stored in their ''vars'' property :
{{ child.vars.label }}

Related

Symfony2 + Twig : Can't access form rows outside "body" block?

i'm a beginner into Symfony2 and i hope that the community could help me and another peoples with this problem.
I have 2 forms sent to the views, that i render these 2 into 2 differents blocks (main-col and left-col), in fact main-col contains user profile form and left-col contains form to upload the profile picture .. This way the profile picture won't appear
But when the profile picture is into the main-col (body block), it works ...
There is some examples for better understand :
This example will NOT work :
{% extends 'FOOBAR\QuoteMachineBundle::base.html.twig' %}
{% block menu -%}
{% include 'FOOBAR\QuoteMachineBundle::CompanyProfile/menu.html.twig' %}
{% endblock %}
{% block title -%}Edit company{% endblock %}
{% block leftcol -%}
<h3>Company Logo</h3>
{{ form(picture_form) }}
Current Picture :<br/>
<img class="opttool" src="{{ entity.pictureWebPath }}" alt="" />
{% endblock %}
{% block body -%}
{{ form(form) }}
{% endblock %}
But this one WILL
{% extends 'FOOBAR\QuoteMachineBundle::base.html.twig' %}
{% block menu -%}
{% include 'FOOBAR\QuoteMachineBundle::CompanyProfile/menu.html.twig' %}
{% endblock %}
{% block title -%}Edit company{% endblock %}
{% block leftcol -%}
{% endblock %}
{% block body -%}
{{ form(form) }}
<h3>Company Logo</h3>
{{ form(picture_form) }}
Current Picture :<br/>
<img class="opttool" src="{{ entity.pictureWebPath }}" alt="" />
{% endblock %}
I switched the "current picture form" from leftcol to body ... In fact forms only works in body block.
I should precise that I can use normal variables into leftcol block and that will work.
The form in leftcol will be an "empty" form element with that only children element :
<input type="hidden" name="_method" value="PUT">
How I can render picture_form correctly into leftcol block ??
EDIT : Like you asked, i published sample of my base.html.twig
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<div class="container">
{% if block('leftcol') is not empty %}
<div class="left-col">{% block leftcol %}{% endblock %}</div>
{% endif %}
<div class="col-main">
<h1>{{ block('title') }}</h1>
<article>
{% block body %}{% block fos_user_content %}{% endblock fos_user_content %}{% endblock %}
</article>
</div>
{% if block('rightcol') is not empty %}
<div class="right-col">{% block rightcol %}{% endblock %}</div>
{% endif %}
</div>
</body>
</html>
Thanks !
I am not 100% sure it will solve your problem but using the block method in a IF statement leads to a new request (meaning everything gets called twice). You should try this:
{% set _block = block('leftcol') %}
{% if _block is not empty %}
<div class='left-col'> {{ _block|raw }} </div>
{% endif %}
Instead of
{% if block('leftcol') is not empty %}
<div class="left-col">{% block leftcol %}{% endblock %}</div>
{% endif %}
And do keep in mind that you should put that kind of logic in your controllers whenever possible.
If I had to make an educated guess, I would say SF/twig are somehow confused by the rendering of two forms inside the same template/block simultaneously. I can't test these two leads right now, but here's what I would try if I were you :
Be more precise when calling your two forms in the twig view :
<form action="foo" method="post" etc...>
{{ form(form_picture) }}
{{ form_rest(form_picture) }}
{{ form_end(form_picture) }}
Symfony's form rendering is highly customizable, find all the details here if you haven't discovered them yet : How to Customize Form Rendering
Use a specific controller, or at least a separate template for at least one of your forms, ideally for each of your forms (but that's a personnal preference) :
{% block leftcol %}
{% render(controller('upload_picture') %}
// or
{% include('upload_picture_form.html.twig', with('form':'form_picture') %}
// Pardon my pseudo-code :P
{% endblock %}
{% block body %}
{{ form(form) }}
{% endblock %}

Overriding the form rendering template according to the items

For example
I have two members in form object.
form_widget(form.icon)
form_widget(form.name)
I have changed 'choice_widget_expanded'
{% block choice_widget_expanded %}
{% spaceless %}
<table {{ block('widget_container_attributes') }}>
{% for child in form %}
<tr>
{{ form_widget(child) }}
{{ form_label(child) }}
</tr>
{% endfor %}
</table>
{% endspaceless %}
{% endblock choice_widget_expanded %}
However I would like to make it affect on {{form.icon}} only
is it possible ? how can I tell the object passed to this block is form.icon or form.name?
To override label block for choice_widget_expanded you can define your block and use it like in below
{% block choice_widget_expanded %}
{% spaceless %}
<table {{ block('widget_container_attributes') }}>
{% for child in form %}
<tr>
{{ form_widget(child) }}
{{ form_label_custom(child) }}
</tr>
{% endfor %}
</table>
{% endspaceless %}
{% endblock choice_widget_expanded %}
And for the custom label too form_label_custom
Note now for every choice field with expanded property (not all
fields) your new label will be in action
{% block form_label_custom %}
{% spaceless %}
{% if label is not sameas(false) %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %} /* you can skip this part for td */
{% endif %}
{% if required %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
<td {% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</td>
{% endif %}
{% endspaceless %}
{% endblock form_label_custom %}
Or even more you can define the custom form_widget_custom(child) block to override like
{% block form_widget_custom %}
{% spaceless %}
{% if compound %}
{{ block('form_widget_compound') }}
{% else %}
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget_custom %}
And now render your field
{{ form_widget_custom(form.icon) }}

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?

How do I apply custom rendering to all form fields except for certain field types in a Symfony 2.1 project

I have created a form theme for my project with the following contents:
{% block field_row %}
<div class="row">
{{ form_errors(form) }}
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
</div>
{% endblock field_row %}
I apply this theme to the project globally and now all my form fields get the additional css class 'form-control'.
I now however want to limit this override to only form fields that are not choice & checkbox field types. How do I do this?
I was a bit annoyed when I did something similar as it was more complicated than I thought it should have been.
There may be a better way but this is what worked for me.
{% block form_row %}
{% set choice = false %}
{% if not form.vars.compound %}
{% for prefix in form.vars.block_prefixes %}
{% if prefix == 'choice' %}
{% set choice = true %}
{% endif %}
{% endfor %}
{% endif %}
{% if choice %}
<div class="row">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% else %}
<div class="row">
{{ form_errors(form) }}
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
</div>
{% endif %}
{% endblock form_row %}
I would recommend using form_row instead of form_field to ease any future transition to to 2.3+ as form_field has been remove from symfony 2.3+ but form_row works in 2.1.

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!