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...).
Related
I have
<div>
<div id="page-wrapper" class="sidebar-content white-bg">
<div class="row border-bottom">
{% include '/layouts/navbar.html.twig' %}
</div>
{% block body %}{% endblock %}
</div>
</div>
Now in this /layouts/navbar.html.twig theres an anchor tag, who's href attribute heavily depends on which template is rendered below, for example if its the Posts template, the href should be /posts/new, if its the announcements template, the href should be /announcements/newand so on, is that even possible?
You could make use of the global variable _self to solve this e.g.
main.twig
{% include "foo.twig" %}
{% include "bar.twig" %}
foo.twig and bar.twig
<div>
<div id="page-wrapper" class="sidebar-content white-bg">
<div class="row border-bottom">
{% include "nav.twig" with { 'template': _self, } %}
</div>
{% block body %}{% endblock %}
</div>
</div>
nav.twig
{% set path = '' %}
{% if template == 'foo.twig' %}
{% set path = 'path/to/foo' %}
{% elseif template == 'bar.twig' %}
{% set path = 'path/to/bar' %}
{% endif %}
{% for i in 0..3 %}
{{ i }}
{% endfor %}
demo
If the path is the only thing that depends on the current template, I'd modify DarkBee's example to just simply pass the path from the parent template. That way you don't need the if/else structure:
posts.twig:
<div>
<div id="page-wrapper" class="sidebar-content white-bg">
<div class="row border-bottom">
{% include "nav.twig" with { 'path': '/posts/new' } %}
</div>
{% block body %}{% endblock %}
</div>
</div>
announcements.twig:
<div>
<div id="page-wrapper" class="sidebar-content white-bg">
<div class="row border-bottom">
{% include "nav.twig" with { 'path': '/announcements/new' } %}
</div>
{% block body %}{% endblock %}
</div>
</div>
nav.twig:
{% for i in 0..3 %}
{{ i }}
{% endfor %}
I was trying to solve my problem: I'm not able to find where the validation errors of register_content.html.twig are defined.
I need to know how to show that errors as I would like. Nowadays my Register is looks like:
As you can see, there is a ugly validation error. I want to change the tags
<div>
<ul><li> Las dos contraseñas no coinciden. </li></ul>
</div>
predefined somewhere, by another.
I have overridden the view register_content.html.twig and I can to show that validation errors but not customize it.
<div>
{{ form_errors(form.email) }}
{{ form_errors(form.username) }}
{{ form_errors(form.plainPassword.first) }}
{{ form_errors(form.plainPassword.second) }}
</div>
Do you know how I can customize HTML structure of the validation errors?
For example in login_content.html.twig the validation errors are shown like this:
It is possible because in login_content.html.twig are defined the validation errors:
{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
You will have to override the default symfony form error block.
You can find out how to do it in the symfony documentation
you will be able to set this form theme globaly or per view as shown in the documentation
So for example if you would like to display the errors inside a div with a class alert alert-danger you would create a file views/Form/form_errors.html.twig
{% form_theme form _self %}
{# form_errors.html.twig #}
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<div class='alert alert-danger'>
{% for error in errors %}
<div>{{ error.message }}</div>
{% endfor %}
</div>
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
and to use this custom theme just in the registration form you would call at the top of your override file register_content.html.twig
{% form_theme form 'Form/form_errors.html.twig' %}
I found the solution. I have change the {{ form_error }} variable in Twig for form.field.vars.errors.
An example, If you want to customize your email validation errors:
<div>
{{ form_errors(form.email) }}
</div>
change it by:
{% for errorItem in form.email.vars.errors %}
<div>{{ errorItem.message }}</div>
{% endfor %}
You could use a div tag or whatever tag you want.
You can use translation. In parameters.ini set locale to your language and create message file. Then in twig template use:
{% if error %}
<div class="error">{{ error.message|trans({},'messages') }}</div>
{% endif %}
Another solution would be:
{{ error.message | replace({"Bad credentials." : "Invalid username or password."}) }}
I have a problem with errors display in my twig templates.
Here is my twig with one nested form form.pictures :
{{ form_start(form) }}
{% if not form.vars.valid %}
<div class="flash-errors-wrapper">
{{ form_errors(form) }}
<div class="form-errors">{{ form_errors(form.pictures) }}</div>
</div>
{% endif %}
{% for formChild in form.pictures %}
<div class="child">
{% if not formChild.vars.valid %}
<div class="flash-errors-wrapper">
{{ form_errors(form) }}
<div class="form-errors">{{ form_errors(form.picture) }}</div>
<div class="form-errors">{{ form_errors(form.caption) }}</div>
</div>
{% endif %}
{{ form_widget(formChild.picture) }}
{{ form_widget(formChild.caption) }}
</div>
{% endfor %}
{{ form_end(form) }}
After submission, when a child form is non valid, my parent form is not valid too.
Problem is that it display empty div on top like :
<div class="flash-errors-wrapper">
<div class="form-errors"></div>
</div>
I don't want that because css exist on flash-errors-wrapper class so style is applied.
Any ideas?
You certainly need to check if one child form is not valid when you check if the parent form is valid. One way to do it would be (Untested, it may need some adaptation):
{% if not form.vars.valid %}
{% set all_childs_valid = True %}
{% for formChild in form.pictures %}
{% if not formChild.vars.valid %}
{% set all_childs_valid = False %}
{% endif %}
{% endfor %}
{% if all_childs_valid %}
<div class="flash-errors-wrapper">
{{ form_errors(form) }}
<div class="form-errors">{{ form_errors(form.pictures) }}</div>
</div>
{% endif %}
{% endif %}
I usually display form errors just as described in docs:
{% if errors|length > 0 %}
<ul>
{% for error in errors %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
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>