I would like to override a specific element of my Symfony form, while allowing my standard template to generate the rest of the fields. So far it has been a case of either/or.
First my template generates the form element
<form action="" method="post" {{ form_enctype(form) }} autocomplete="off">
{% form_theme form 'SuperSecretProjectBundle:Default:collection.html.twig' %}
{{ form_widget(form) }}
<input type="submit" class="right submit button primary small" value="Save" />
</form>
Inside collection.html.twig I have the following blocks: form_row is the generic widget renderer, while image_sets_row is my specific row I want to override.
{% block form_row %}
<div class="row">
<div class="large-12 columns{% if not form.vars.valid %}error{% endif %}">
{{ form_label(form) }}
{{ form_widget(form) }}
<small>{{ form_errors(form) }}</small>
</div>
</div>
{% endblock form_row %}
{% block image_sets_row %}
<div id="image_sets">
<div class="row">
<div class="columns large-12">
Add image set
</div>
</div>
</div>
{% endblock %}
This results in using form_row for all fields, without my modified block. How can I have Symfony output the elements that are not being specifically overridden and include my new blocks as well?
What you need is a custom field type for the field you are trying to use your custom widget for.
As shown in the link, first you need to create a custom Field Type class like so
// src/AppBundle/Form/Type/ImageSetsType.php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; #should change to whatever parent type you need
class ImageSetsType extends AbstractType{
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults( array() ); #set any option defaults you need here
}
public function getParent(){
return ChoiceType::class; #again change this to whatever parent type you need
}
}
Next we get your template for that block working properly
{# app/Resources/views/form/fields.html.twig #}
{% block imagesets_widget %}
<div id="image_sets">
<div class="row">
<div class="columns large-12">
{{ form_label(form) }}
{{ form_widget(child) }}
Add image set
<small>{{ form_errors(form) }}</small>
</div>
</div>
</div>
{% endblock %}
Then you use your newly created type in your form as you would any other.
As I assume you want a little more in
Related
I am trying to display a list of courses with a checkbox allowing the user to select any number of courses from the list. I am new to Symfony and trying to follow the form approach but do not understand how to display additional attributes of an object beyond using the choice_label.
If I were just passing the course objects, I could simply use:
Template:
<form>
{% for course in courses %}
<div class="row">
<div><input type="checkbox" name="course[]" value="{{ course.id }}"></div>
<div>{{ course.name }}</div>
<div>{{ course.description }}</div>
<div>{{ course.semester }}</div>
</div>
{% endfor %}
</form>
Using the form builder, it seems my template would look like this:
{{ form_start(form) }}
<div class="row">
<div>{{ form_row(form.courses) }}</div>
</div>
{{ form_end(form) }}
How can I access these additional object attributes (name, description, etc.) within the form row? Is there a reason to use to the form builder in this case instead of the first 'by hand' approach? In summary, I need granular control of the object attributes within a given form row and the choice_label attribute alone does not seem sufficient. What is a potential solution?
First, for accessing each option of the choice label, it's fairly simple... because the form.courses is an array.
You can access individual checkbox by doing this :
{{ form_widget(form.courses[0]) }}
And you can use a loop to access them individually. And for customizing the rendering of your forms, you can use form_errors, form_label and form_help functions, so your final code will be something like this :
{{ form_start(form) }}
{{ form_errors(form) }}
{% for course in form.courses %}
<div class="row">
{{ form_widget(course) }}
{{ form_label(course) }}
</div>
{% endfor %}
{{ form_help(form.courses) }}
{{ form_end(form) }}
Note: The label is the key value in the array passed to the « choices » option in Form Builder.
Sources:
How to Customize Form Rendering : https://symfony.com/doc/current/form/form_customization.html
On my Symfony 3.2 project I extended the FosUserBundle's on a file named messages.en.yml that has the following content:
security.login.username: "Username"
security.login.password: "Password"
security.login.remember_me: "Remember me"
security.login.submit: "Login"
registration.confirmed.header: "Registration Success"
reset.password.header: "Reset your password"
Please keep in note that the registration.confirmed.header and reset.password.header are used in the template that I extend from fos user bundle such as the request.html.twig that has the following content:
{% extends "#FOSUser/layout.html.twig" %}
{% set body_css_classes="skin-blue layout-top-nav" %}
{% trans_default_domain 'FOSUserBundle' %}
{% block title %} Set a new Password {% endblock %}
{% block fos_user_content %}
<div class="content-wrapper" style="min-height:100%">
<div class="container">
<section class="content">
<div class="box box-default">
<div class="box-header">
<h4 class="text-center">{{ 'reset.password.header'|trans }}</h4>
</div>
<form action="{{ path('fos_user_resetting_send_email') }}" method="POST" class="form-horizontal">
<div class="box-body">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">{{ 'resetting.request.username'|trans }}</label>
<div class="col-sm-9">
<input type="text" id="username" class="form-control" name="username" required="required" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" class="btn btn-primary" value="{{ 'resetting.request.submit'|trans }}" />
</div>
</div>
</div>
</form>
</div>
</section>
</div>
</div>
{% endblock fos_user_content %}
{% block javascriptsFooter %}
{% endblock %}
The problem is that everything gets translated except the reset.password.header that even though I put it into the messages.yml it still does not translate the extra messages I set.
{% trans_default_domain 'FOSUserBundle' %}
This means, that the translator is not looking in the domain "messages" but "FOSUserBundle". Adding the translations in /app/Resources/translations/FOSUserBundle.en.yml should work.
As #kero says the translation file must be named FOSUserBundle.en.yml and must have full path: app/Resources/translations/FOSUserBundle.en.yml
Also ensure that you have set the correct keys and do not override any existing one eg. As you can see in a FOSUserBundle.xx.yml file under vendor/friendsofsymfony/Resources/translations/ folder there is no way to set a key change_password.submit.something and expect to get translated correctly.
I have read the Symfony 2 documentation and I'm trying to make a custom embedded form and I can't understand the provided code in the documentation.
Official documentation:
http://symfony.com/doc/current/cookbook/form/form_customization.html
Specifically the code that i don't understand is this:
{% form_theme form _self %}
{% block _tasks_entry_widget %}
<tr>
<td>{{ form_widget(task.task) }}</td>
<td>{{ form_widget(task.dueDate) }}</td>
</tr>
{% endblock %}
after many tests I've noticed that '_task_entry' is the name of the embedded form (not the name of field in the main form)
Now I'm trying to get what is the 'task' variable, {{ form_widget(task.dueDate) }}
I've tried with the embedded form name again, with the name of the entity field, and with the name of the main form variable but nothing works:
{% form_theme edit_form.lineas _self %}
{% block zb_gestionbundle_lineaalbaran_widget %}
<div class="large-1 small-1 columns">
{{ form_widget(form.cantidad) }}
</div>
<div class="large-8 small-8 columns">
{{ form_widget(form.concepto) }}
</div>
<div class="large-2 small-2 columns">
{{ form_widget(form.precio) }}
</div>
{% endblock %}
{{ form_label(edit_form.lineas) }}
{{ form_errors(edit_form.lineas) }}
{{ form_widget(edit_form.lineas) }}
In summary, What I need to put in {{ form_widget(form.cantidad) }} for make the code works?
Tyvm!!
One possible solution:
After investigate a little more, I've found this code that works!
{% form_theme edit_form _self %}
{% macro prototype(linea) %}
<div class="large-1 small-1 columns">
{{ form_widget(linea.cantidad) }}
</div>
<div class="large-8 small-8 columns">
{{ form_widget(linea.concepto) }}
</div>
<div class="large-2 small-2 columns">
{{ form_widget(linea.precio) }}
</div>
{% endmacro %}
{% for linea in edit_form.lineas %}
{{_self.prototype(linea)}}
{% endfor %}
I don't know if the documentation is wrong, I leave the answer open for the doubt about the documentation.
Your solution work ! Just to complete, i had the same problem but the documentation is correct ! Just a little bit difficult to understand.(in my opinion).
To use the documentation solution :
you have to know the unique_block_prefix of your embbeded form.
To do this : add this to your code {{dump(form)}} and search the unique_block_prefix of your embedded form.
then you just have to replace the example of documentation like this :
{% form_theme form _self %}
{% block _zb_gestionbundle_lineaalbaran_entry_widget %}
<div class="large-1 small-1 columns">
{{ form_widget(form.cantidad) }}
</div>
<div class="large-8 small-8 columns">
{{ form_widget(form.concepto) }}
</div>
<div class="large-2 small-2 columns">
{{ form_widget(form.precio) }}
</div>
{% endblock %}
<!--block with your html/twig code, form, etc ..-->
{% block your_main_block %}
...
<!--your form-->
...
<!-- the embbeded part -->
{{form_row(form.lineas)}}
...
{% endblock %}
To sum up, generally the unique_block_prefix is
_(id of your embedded form)_entry_widget
And you just have to replace like the example of the doc.
I hope you understand and i miss nothing(sorry for my english...).
I have the a form twig template, where I want to parse a specific fields help text with the raw filter (it contains html). The field is called postcode in a form called Clinic
According to here http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field
Form template:
{% extends 'AgriHealthAhpBundle::admin.html.twig' %}
{% form_theme form 'AgriHealthAhpBundle:Form:fields.html.twig' %}
{% block _clinic_postcode_row %}
<div class="row">
test<div class="small-12 medium-3 columns label">{{ form_label(form) }}</div>
<div class="small-12 medium-6 columns widget">
{{ form_widget(form) }}
<div class="error">
{{ form_errors(form) }}
</div>
</div>
<div class="small-12 medium-3 columns help">
{% if help is defined %}
{{ help|raw }}
{% endif %}
</div>
</div>
{% endblock %}
{% block admin -%}
<h1>New Clinic</h1>
{{ form(form) }}
<div class="row form_actions">
<div class="small-12 medium-offset-3 medium-2 columns submit">
<button type="submit" id="agrihealth_ahpbundle_clinic_submit_visible" name="agrihealth_ahpbundle_clinic[submit]">Create</button>
</div>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#agrihealth_ahpbundle_clinic_submit_visible').click(function(){
jQuery('form[name="agrihealth_ahpbundle_clinic"]').submit();
});
});
</script>
<div class="small-12 medium-2 columns cancel">
<a href="{{ path('clinic') }}">
Cancel
</a>
</div>
<div class="small-12 medium-2 end columns cancel">
<a href="{{ path('clinic') }}">
Back to List
</a>
</div>
</div>
{% endblock %}
AhpBundle/Resources/views/Form/fields.html.twig
{% block form_row %}
{% spaceless %}
<div class="row">
<div class="small-12 medium-3 columns label">{{ form_label(form) }}</div>
<div class="small-12 medium-6 columns widget">
{{ form_widget(form) }}
<div class="error">
{{ form_errors(form) }}
</div>
</div>
<div class="small-12 medium-3 columns help">
{% if help is defined %}
{{ help }}
{% endif %}
</div>
</div>
{% endspaceless %}
{% endblock form_row %}
Anyone can see what I have overlooked, I tried
{% block _clinic_postcode_row %}
and
{% block _Clinic_postcode_row %}
Solution
As per accepted answer, the form row block needs to fully idetified with shorthand bundle name. The easiest way is to view the source code of the form and identify the text used in each input field and the form name="":
Replace
{% form_theme form 'AgriHealthAhpBundle:Form:fields.html.twig' %}
with
{% form_theme form with ['AgriHealthAhpBundle:Form:fields.html.twig', _self] %}
Since you are decorating the row inside action template, while applying separate form template you need to specify multiple templates
You also need to specify a fully qualified path name to your row block such as
{% block _agrihealth_ahpbundle_clinic_postcode_row %}
I'm creating a form in Symfony2 that contains more than one submit button. I need to control where these buttons are rendered. I tried the following, but naturally nothing happens.
<h1>Search Form</h1>
<div id="search_form">
{{ form(formSearch) }}
</div>
<div id="search_tasks">
Tasks:
{{ form_widget(formSearch.searchButton1) }}
{{ form_widget(formSearch.searchButton2) }}
</div>
The search buttons are declared in the form class; they are rendered inside #search_form and nothing shows up in #search_tasks.
You are already rendering the whole form with {{ form(formSearch) }} (fields and buttons are only rendered once).
You need to render the start, rows and end separately.
{{ form_start(formSearch) }}
<h1>Search Form</h1>
<div id="search_form">
{{ form_row(formSearch.field1) }}
{{ form_row(formSearch.field2) }}
{{ form_row(formSearch.field3) }}
</div>
<div id="search_tasks">
Tasks:
{{ form_widget(formSearch.searchButton1) }}
{{ form_widget(formSearch.searchButton2) }}
</div>
{{ form_end(formSearch) }}
I ran into the same issue where I needed my Submit and Reset buttons to be on the same row. My forms are dynamic so there was no way I could output the fields individually. I captured the buttons' HTML first so that form_widget(form) wouldn't output them for me.
{% form_theme form 'AppBundle::form/form_layout.html.twig' %}
<div class="row">
{{ form_start(form) }}
{% if form.submit is defined %}
{% set submitButton = form_widget(form.submit) %}
{% endif %}
{% if form.reset is defined %}
{% set resetButton = form_widget(form.reset) %}
{% endif %}
{{ form_widget(form) }}
<div class="form-group row">
{% if submitButton is defined %}
{{ submitButton|raw }}
{% endif %}
{% if resetButton is defined %}
{{ resetButton|raw }}
{% endif %}
</div>
{{ form_end(form) }}
</div>