I am currently working on a small personal project to learn how to manipulate Symfony and Sonata, and I find myself confronted with a small problem. I have constrained one of my variables to a "template" in "configureListFields" but I can not submit it to "editable". I can do the one without the other but not both at the same time if not the "editable" bug as I show you a bit further down.
List :
$listMapper->add('status', 'string', array(
'template' => 'WebBundle:Default:list_client.html.twig',
'label'=> 'Status'))
Form :
$formMapper->add('Status', 'choice', array(
'choices' => array(
'Client' => 'Client',
'Ex-Client' => 'Ex-Client',
'Prospect' => 'Prospect')))
Template :
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
<div>
<p class="ClientStatus {% if object.Status == 'Ex-Client' %}
label label-danger
{% elseif object.Status == 'Client' %}
label label-success
{% else %}
label label-info
{% endif %}" >
{{ object.Status }}
</p>
</div>
{% endblock %}
View with that config :
Second config :
$listMapper->add('status', 'choice', array(
'choices'=>array(
"Client"=>"Client",
"New Client"=>"New Client",
"Ex-Client"=>"Ex Client"
),
'label'=> 'Status',
'editable'=>true))
View :
Third Config :
->add('status', 'choice', array(
'choices'=>array(
"Client"=>"Client",
"New Client"=>"New Client",
"Ex-Client"=>"Ex Client"
),
'template' => 'WebBundle:Default:list_client.html.twig',
'label'=> 'Status',
'editable'=>true))
view :
So there seems to be a conflict between "template" and "editable" opinions on how to handle this problem ?
Thanks a lot.
check out the list_choice template that is provided with the Sonata sources.
# SonataAdminBundle/Resources/views/CRUD/list_choice.html.twig
{% set is_editable =
field_description.options.editable is defined and
field_description.options.editable and
admin.hasAccess('edit', object)
%}
{% set x_editable_type = field_description.type|sonata_xeditable_type %}
{% if is_editable and x_editable_type %}
{% block field_span_attributes %}
{% spaceless %}
{{ parent() }}
data-source="{{ field_description|sonata_xeditable_choices|json_encode }}"
{% endspaceless %}
{% endblock %}
{% endif %}
They check if the field is editable and add data-source attribute to the field_span_attributes block of the parent base_list_field template part:
<span {% block field_span_attributes %}class="x-editable"
data-type="{{ xEditableType }}"
data-value="{{ data_value }}"
data-title="{{ field_description.label|trans({}, field_description.translationDomain) }}"
data-pk="{{ admin.id(object) }}"
data-url="{{ url }}" {% endblock %}>
{{ block('field') }}
</span>
So try adding the data-source in your custom template as well.
This answer worked for me:
If you check the HTML code, on your element choice, of your site you can detect if any tag is missing, for example the code below is the code that generate the page without the 'template' option configured:
<span class="x-editable label-info editable editable-click editable-open" data-type="select"
data-value="Rechazado"
data-title="Estado"
data-pk="4"
data-url="/eventos/web/app_dev.php/admin/core/set-object-field-value?context=list&field=estado&objectId=4&code=admin.evento"
data-source="[{"value":"Aprobado","text":"1"},{"value":"Pendiente","text":"Pendiente"},{"value":"Rechazado","text":"Rechazado"}]" data-original-title="" title="" aria-describedby="popover786605">
</span>
And now check the code generated when the 'template' option is on set
<span class="x-editable label label-danger editable editable-click"
data-type="select"
data-value="Rechazado"
data-title="Estado"
data-pk="4"
data-url="/eventos/web/app_dev.php/admin/core/set-object-field-value?context=list&field=estado&objectId=4&code=admin.evento">
</span>
The data-source field is missing and that is the reason why its crash.
The solution is simple (isn't the best but it is something) on your template add the data-source with the data of your choice.
Related
I have an issue with rendering an Entity Type in a Symfony Form.
Here is what I call in the form type:
$builder
->add('categories', EntityType::class, array
(
'class' => 'AppBundle\Entity\ArticleCategory',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
'constraints' => array
(
new NotBlank(array('message' => 'Select Category'))
)
))
This is the template I am trying to do:
{% form_theme form _self %}
{% block _article_categories_entry_row %}
<div class="ckbox ckbox-default">
{{ form_widget(form) }}
{{ form_label(form) }}
{{ form_errors(form) }}
</div>
{% endblock %}
In the same template I am doing
{{ form_start(form) }}
{{ form_row(form.categories) }}
{{ form_end(form) }}
The weird thing happens when I use block _article_categories_entry_widget and it picks it up however it renders the label twice. Any ideas how to manage to situation ? In this scenario above it doesn't render or adds the ckbox class at all ! :(
You can loop through your form.categories in template as below and render checkboxes as you want.
{{ form_start(form) }}
{% for category in form.categories %}
{{ form_label(category) }}
{{ form_widget(category) }}
{% endfor %}
{{ form_end(form) }}
As you named your custom block _article_categories_entry_row, I assume, your form is named ArticleType.
The custom block for a specific form field should be named with following pattern:
_<form_name>_<field_name>_<part_name>
Possible parts as row, errors, widget, label. You're using row here.
But the entry part of block name is unnecessary.
Try with:
{% block _article_categories_row %}
You can find more details in Symfony Documentation
I have two entities: Supplier and Category joined ManyToMany.
Next, I have a form builder class where I add EntityType::class.
Category structure:
id, categoryName, parentId - where parentIds value can be:
0 - head category
1 - subcategory
etc
I need to display (in twig template) categories with structure:
Category1
Subcategory1
Subcategory2
Category2
Subcategory3
Subcategory4
etc. where Category are some kind of header and subcategory are checkboxes.
Please somebody give me a tip how to do this.
Building on what we discussed in the comments, the following worked in my test environment:
InSupplierType::buildForm:
->add('categories', EntityType::class, [
'class' => Category::class,
'choice_label' => 'name',
'group_by' => 'parent',
'multiple' => true,
'expanded' => true
])
Though without form customization this would only render the checkboxes without headers. This is discussed here: https://github.com/symfony/symfony/issues/5489#issuecomment-194943922
Implementing the fix by MaxE17677 the view would look something like this:
{% extends 'base.html.twig' %}
{% form_theme form _self %}
{# #see: https://github.com/symfony/symfony/issues/5489#issuecomment-194943922 #}
{%- block choice_widget_expanded -%}
<div {{ block('widget_container_attributes') }}>
{% for name, choices in form.vars.choices %}
{% if choices is iterable %}
<label class="choice_category">
<strong>
{{ choice_translation_domain is same as(false) ? name : name|trans({}, choice_translation_domain) }}
</strong>
</label>
<div>
{% for key,choice in choices %}
{{ form_widget(form[key]) }}
{{ form_label(form[key]) }}
{% endfor %}
</div>
{% else %}
{{- form_widget(form[name]) -}}
{{- form_label(form[name], null, {translation_domain: choice_translation_domain}) -}}
{% endif %}
{% endfor %}
{%- endblock choice_widget_expanded -%}
{% block body %}
<div class="container">
{{ form_start(form) }}
{{ form_row(form.categories) }}
{{ form_end(form) }}
</div>
{% endblock %}
Preview:
The crucial thing is that you use group_by feature of the ChoiceType. To get this to work with your current entities you might need to also use the query_builder setting of EntityType. Something like:
// ...
'query_builder' => function (EntityRepository $er) {
return $er
->createQueryBuilder('c')
->where('c.parentId = 1')
;
},
along with:
// ...
'group_by' => function ($category) {
// *pseudo-code*
return $category->getParent()->getName();
}
I want to auto-check check boxes in the HTML. I've managed to get this to work, but it's kinda messy in the template:
<ul>
{% for tag in tags %}
{% set selected = false %}
{% for article_tag in article.tags %}
{% if article_tag.id == tag.id %}
{% set selected = true %}
{% endif %}
{% endfor %}
<li><input type="checkbox" name="tags[]" value="{{ tag.id }}" {% if selected %}checked{% endif %}> {{ tag.name }}</li>
{% endfor %}
</ul>
So the data I'm loading in is like this (in JSON format):
[
'tags' => [
{'id'=> 1, 'name'=>'Travel'},
{'id'=> 2, 'name'=>'Cooking'},
],
'article' => {
'tags' => [
{'id'=> 1, 'name'=>'Travel'},
],
}
]
Also, I'm not using Symfony (I'm using Slim's Twig library) so not sure if Symfony has some stuff in it's framework for doing stuff with Twig. If so, it won't work for me :(
The problem is the article is an array, so or you need to cycle on it for every tags array that contain or you simply access on it of the first element as follow:
{% for article_tag in article[0].tags %}
Instead of:
{% for article_tag in article.tags %}
See the result on this working twigfiddle
Hope this help
I'm using symfony 2.3
I have form with field of type "collection"
Visualization code in twig:
{% for field in form.fields %}
{{ form_row(field.name) }}
{% endfor %}
Everything work, expect when form.fields is empty.
Then nothing is visualized in twig loop, witch is fine.
But at the end of the form there is "label" for the element "form.fields". Only label.
Workaround:
{% for field in form.fields %}
{{ form_row(field.name) }}
{% endfor %}
<div class="hidden">
{{ form_row(form.fields) }}
If there are elements, they will be rendered in the loop.
{{ form_row }} will be empty, because all elemets are iterated in the loop above.
But if form.fields is empty then there is "hidden" (in the div) label.
What I'm missing !? Why this is happening !?
Hidden div content:
<div class="form-group"><label class="col-sm-2 control-label required">name</label><div class="col-sm-10"><div id="my-id" data-prototype=""></div></div></div>
Builder config:
$builder->add(
'fieldDataMappers',
'collection',
array(
'type' => new FieldDataType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
)
);
As you have correctly guessed, the Symfony TwigBridge keep track of what is rendered and what is not. This is useful, since there is a function called form_rest(form), which is especially useful for printing hidden form field, and to prevent the "great jupiter! I forgot to print that field!" moments. :) You often find form_rest at the end of the form, just before the submit button.
Also consider that the collection IS a composite form type, which contains a variable list of child form. When the for loop is not triggered, since the form type is empty, the call to {{ form_row(form.fields) }} print out the collection form type. By default, this will print (you've guessed it) the collection label and an empty div. On the other hand, when the collection is not empty, Symfony will consider the collection as rendered, since all children are already rendered (see FormView::isRendered)
You can take a look into Symfony standard theme form_div_layout.html.twig, especially the blocks form_row (which show label printing) and form_widget_compound (the div and the for loop).
So, if you just need to hide the label (quick and dirty, some div are still there), just use:
$builder->add(
'fieldDataMappers',
'collection',
array(
'type' => new FieldDataType(),
'label' => false,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
)
);
Or better, simply output the whole collection widget, without row:
{{ form_widget(form.fieldDataMappers) }}
Or even better, you print the whole collection with:
{{ form_row(form.fieldDataMappers) }}
...and then add a Twig theme to customize the collection output with something like (note the name syntax, and the missing form_label call):
{% block collection_row -%}
<div>
{{- form_errors(form) -}}
{{- form_widget(form) -}}
</div>
<div class="hidden">Something here?</div>
{%- endblock collection_row %}
Hope this help!
{# src/Acme/TaskBundle/Resources/views/Task/new.html.twig #}
{# ... #}
{{ form_start(form) }}
{# render the task's only field: description #}
{{ form_row(form.description) }}
<h3>Tags</h3>
<ul class="tags">
{# iterate over each existing tag and render its only field: name #}
{% for tag in form.tags %}
<li>{{ form_row(tag.name) }}</li>
{% endfor %}
</ul>
{{ form_end(form) }}
{# ... #}
Symfony2 cookbook
http://symfony.com/doc/current/cookbook/form/form_collections.html
Also the field of the collection is named fieldDataMappers not field.
So i think it should be
{% for field in form.fieldDataMappers %}
{{ form_row(field.name) }}
{% endfor %}
{{ form_label(form.emails) }}
<ul id="email-fields-list"
data-prototype="{{ form_row(form.emails.vars.prototype)|e }}"
data-widget-tags="{{ '<ol></ol>'|e }}"
data-widget-counter="{{ form.emails|length }}">
{% for email in form.emails %}
<ol>
{{ form_errors(email) }}
{{ form_row(email) }}
</ol>
{% endfor %}
</ul>
<button type="button" class="add-another-collection-widget" data-list-selector="#email-fields-list">Add email</button>
{{ form_widget(form.emails) }}
I just add {{ form_widget(form.emails) }} after block thant handles adding to collection and no more label on the end of form.
Cheers
I solved this with :
{{ form_label(form.collection) }}
{% for element in form.collection %}
{{ form_widget(element) }}
{% else %}
{{ form_widget(form.collection) }}
{% endfor %}
(a bit late, I know, but still a problem with Symfony 5)
I installed the GregwarCaptcha bundle and add the following code in controller
$form = $this->createFormBuilder()
->add('captcha', 'captcha', array(
'width' => 200,
'height' => 50,
'length' => 6,
));
return $this->render('MyIndexBundle:Default:contact.html.twig',array(
'form' => $form->createView()
));
the following code in template
{% form_theme form 'MyIndexBundle:Default:captcha.html.twig' %}
<form action="" method="post">
........
{{ form_widget(form.captcha) }}
.......
</form>
and the captcha.html.twig is
{% block captcha_widget %}
{% spaceless %}
<img src="{{ captcha_code }}" alt="" title="captcha" width="{{ captcha_width }}" height="{{ captcha_height }}" />
...
{{ form_widget(form, {'attr': { 'autocapitalize': 'off','autocorrect': 'off' }}) }}
...
{% endspaceless %}
{% endblock %}
i am getting "Method "captcha" for object "Symfony\Component\Form\FormView" does not exist" error.
...if i use captcha.html.twig, directily i get captcah-code does not exist...
I manage using gregwar captcha using it like this :
First, Add new Gregwar\CaptchaBundle\GregwarCaptchaBundle(), to your AppKernel.php
Then Add the folowwing code on config.yml
gregwar_captcha:
width: 200
height: 50
length: 6
Then, Add ->add('captcha', 'captcha') to your $builder
Finally, Add {{ form_widget(form.captcha) }} in twig template.
So I didn't use form_theme neither captcha.html.twig
And this is working just fine.