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
Related
In my Symfony 2 app I got the following code rendering the form:
{{ form_start(form) }}
{{ form_errors(form) }}
<div class="form-group">
{{ form_label(form.title) }}
{{ form_widget(form.title) }}
</div>
<div class="form-group">
{{ form_label(form.message) }}
{{ form_widget(form.message) }}
</div>
{% if extras == true %} //this block should be rendered only if extras var is true
<div class="form-group">
{{ form_label(form.description) }}
{{ form_widget(form.description) }}
</div>
{% endif %}
{{ form_end(form) }}
The problem is that I get rendered {{ form_widget(form.description) }} even if my extras var is false, not with all other form fields but somewhere at the bottom of the form which is obviously a bug. How to make it render only if extras is true and disappear completely from the page in case extras is false?
Thank you.
All other form fields are automatically added to the end of your form by default. It triggers {{ form_rest() }} by default. Use this code to prevent this behavior:
{{ form_end(form, {'render_rest': false}) }}
http://symfony.com/doc/current/reference/forms/twig_reference.html#form-end-view-variables
I'm trying to control the rendering of password fields based on whether i'm editing an user or creating one. I'm doing this with a simple session boolean variable as follows:
{{ form_start(userForm) }}
{{ form_errors(userForm) }}
<div id="user-fg-email" class="form-group">
{{ form_label(userForm.email) }}
{{ form_errors(userForm.email) }}
{{ form_widget(userForm.email) }}
</div>
{% if app.session.get('editingUser') == false %}
<div id="user-fg-pp1" class="form-group">
{{ form_label(userForm.plainPassword.first) }}
{{ form_widget(userForm.plainPassword.first) }}
</div>
<div id="user-fg-pp2" class="form-group">
{{ form_label(userForm.plainPassword.second) }}
{{ form_errors(userForm.plainPassword.first) }}
{{ form_widget(userForm.plainPassword.second) }}
</div>
{% endif %}
<div id="user-fg-role" class="form-group">
{{ form_label(userForm.role) }}
{{ form_errors(userForm.role) }}
{{ form_widget(userForm.role) }}
</div>
<button type="submit" class="btn btn-primary pull-right">Submit</button>
{{ form_end(userForm) }}
However when this boolean is evaluated as true, which is supposed to prevent these fields from rendering, they are still being rendered assumingly by the later following form_end tag.
Is there a way to prevent that from happening?
edit:
if editingUser == true the password fields are actually rendered after the button, hence my assumption it's done so by the form_end tag.
Because you have to specify Twig to not display all the rest of the fields which are not explicitly rendered in the form : http://symfony.com/doc/current/reference/forms/twig_reference.html#form-end-view-variables
{{ form_end(form, {'render_rest': false}) }}
I have form:
<form action="{{ path('book_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_start(form) }}
{{ form_row(form.bookFoto) }}
{{ form_row(form.bookTitle) }}
{{ form_row(form.categories) }}
<p class="new_category">+ Add category</p>
{{ form_row(form.authors) }}
<p>+ Add author</p>
{{ form_end(form) }}
When I click 'Add category' I load with AJAX form for create new Category Entity, and save it with AJAX too.
But I don't understand how can I update entity field type categories without reloading form.
To deal with embedded collection you need to manage your form with JS. Symfony has built-in helper for it. It is called prototype and used for populating form with new rows of embedded collection:
<ul class="tags" data-prototype="{{ form_widget(form.categories.vars.prototype)|e }}">
...
</ul>
You can read more at official documentation:
http://symfony.com/doc/current/cookbook/form/form_collections.html
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>
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