I'm trying to create a collection of forms which consists of 3 global parts and and fourth part containing 3 fields that are allowed to be replicated. Both form names are "search". I've no idea what am I doing wrong but in prototype instead of having the whole form created I get the following:
<input type="search" id="search_statistics_collection___name__" name="search[statistics_collection][__name__]" required="required" class="form-control" ><a href='#' class='add-statistic btn'>Dodaj statystykę</a>
View:
{{ form_start(searchForm) }}
{{ form_row(searchForm.league) }}
{{ form_row(searchForm.range) }}
{{ form_row(searchForm.season) }}
<div id="single-proto" data-prototype="{{ form_widget(searchForm.statistics_collection.vars.prototype)|e }}<a href='#' class='add-statistic btn'>Dodaj statystykę</a>"></div>
{% for single in searchForm.statistics_collection %}
<div class="single-statistic">
{{ form_label(single.statistic) }}
{{ form_widget(single.statistic) }}
{{ form_widget(single.sign) }}
{{ form_widget(single.value) }}
Dodaj statystykę
</div>
{% endfor %}
{{ form_end(searchForm) }}
Form class: (relevant parts)
SearchType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('league', 'choice', array(
'label'=>'Wybierz ligi',
'choices'=>array(
'all'=>'Wszystkie ligi',
'favourite'=>'Moje ulubione ligi',
'bookie'=>'Ligi mojego bukmachera'
)
))
->add('range', 'choice', array(
'label'=>'Wybierz zakres',
'choices'=>array(
'all'=>'Cały mecz - wszystkie mecze',
'home'=>'Cały mecz - dom',
'guest'=>'Cały mecz - wyjazd',
'half_all'=>'Do przerwy - wszystkie mecze',
'half_home'=>'Do przerwy - dom',
'half_guest'=>'Do przerwy - wyjazd',
)
))
->add('season', 'choice', array(
'label'=>'Wybierz sezon',
'choices'=>Statistics::$seasons
))
->add('statistics_collection', 'collection', array(
'label'=>'Wybierz statystykę',
'type' => new SearchSubType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
))
->setData(array(
'statistics_collection' => array(
array('', '', ''),
)
))
;
}
SearchSubType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('statistic', 'choice', array(
'label'=>'Wybierz statystykę',
'required'=>false,
'choices'=>Statistics::$statistics
))
->add('sign', 'choice', array(
'label'=>'',
'required'=>false,
'choices'=>array(
'gt'=>'>',
'lt'=>'<',
'eq'=>'=',
'gteq'=>'>=',
'lteq'=>'<='
)
))
->add('value', 'text', array(
'label'=>'',
'required'=>false,
))
;
}
Please help :)
Solution
The subform included within collection has to have other name than parent one. Otherwise it all mess up :)
You should do like:
{{ form_start(searchForm) }}
{{ form_row(searchForm.league) }}
{{ form_row(searchForm.range) }}
{{ form_row(searchForm.season) }}
<ul class="statistics_collection" data-prototype="{{ form_widget(searchForm.statistics_collection.vars.prototype)|e }}"></ul>
{{ form_end(searchForm) }}
and also do't forget to imply jquery in your twig file like this
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
var collectionHolder = $('ul.statistics_collection');
// setup an "add a tag" link
var $addValueLink = $('Upload Pictures');
var $newLinkLi = $('<li></li>').append($addValueLink);
jQuery(document).ready(function() {
// add the "add a statistics_collection" anchor and li to the tags ul
collectionHolder.append($newLinkLi);
$addValueLink.on('click', function(e) {
addValueForm(collectionHolder, $newLinkLi);
});
});
function addValueForm(collectionHolder, $newLinkLi) {
// Get the data-prototype we explained earlier
var prototype = collectionHolder.attr('data-prototype');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on the current collection's length.
var newForm = prototype.replace(/__name__/g, collectionHolder.children().length);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
</script>
{% endblock %}
For more details you may follow How to Embed a Collection of Forms .
Related
im learning symfony. I'm trying to display an image when i select a choice from dropdown menu in the form.
this is my form
$collection = array(
'jewel1' => 'jewel1.jpg',
'jewel2' => 'jewel2.jpg',
.
.
.
)
$builder
->add('product_group_id', HiddenType::class,['data'=> $productId])
->add('jewel_name', TextType::class)
->add('jewel_rotation', IntegerType::class)
->add('price', IntegerType::class)
->add('image_name', ChoiceType::class, [
'label' => 'Jewel Image',
'required' => false,
'choices' => $collection
])
->add('save', SubmitType::class, ['label' => 'Save']);
and this is my twig (i don't know what to do yet)
{% block javascript %}
<script>
$(function() {
$('form.image_name.vars.value').change(
var tt = $(this).val();
alert(tt);
)
})
</script>
{% endblock %}
{% block main %}
{{form_start(form)}}
{{form_widget(form)}}
<div class="jewels">
{% set path = 'customRing/jewel/' ~ form.image_name.vars.value ~%}
{{form.image_name.vars.value}}
<img src="{{ asset(path, 'save_image') }}" width="200" height="200"/>
</div>
{{form_end(form)}}
{% endblock %}
so when i select one choice in the dropdown menu, the preview image will be display so i can press the submit button with the right image.
however, I have no idea how i can get a changed value from choicetype before sumbit.
You can get the changed value of the select via javascript and display it in the img tag
<script>
document.getElementById('YOUR_IMAGE_SELECT').addEventListener('change', function() {
document.getElementById('YOUR_IMG').src = "customRing/jewel/" + this.value;
});
</script>
I have a Symfony Form for a file upload looking like
$builder
->add('imageFile', FileType::class, [
'mapped' => false,
'required' => false,
'label' =>'user.edit.select_image',
'constraints' => $coverConstraints
])
->getForm();
because of a bug in bootstrap 4 i have to theme it so it can show Select a file to upload in the box
{% set tr = 'user.edit.select_image|trans' %}
<div class="card-body">
{{ form_start(CoverForm) }}
{{ form_row(CoverForm.imageFile, {
attr: {
'placeholder': tr
}
}) }}
{{ form_errors(CoverForm) }}
{{ form_widget(CoverForm) }}
<button type="submit" class="btn btn-dark">{{ 'user.edit.form_submit'|trans }}</button>
{{ form_end(CoverForm) }}
</div>
<script>
$('.custom-file-input').on('change', function(event) {
var inputFile = event.currentTarget;
$(inputFile).parent()
.find('.custom-file-label')
.html(inputFile.files[0].name);
});
</script>
My problem is that that variable tr doesn't executed
Do you have any ideea how to aproach this ?
{% set tr = 'user.edit.select_image'|trans %}
As trans is a filter.
So I have this simple form:
class CreditType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('credits', EntityType::class, [
'class' => Product::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('product')
->orderBy('product.amount');
},
'expanded' => true,
'choice_label' => function ($key) {
return $key->amount.' credits voor maar '.$key->price;
}
]);
}
}
which I use in the following Controller:
public function credits(Request $request)
{
$form = $this->createForm(CreditType::class);
$form->handleRequest($request);
if ($form->isSubmitted()) {
throw new \Exception('It works!');
}
return $this->render(
'credits/credits_widget.html.twig',
[
'form' => $form->createView(),
]
);
}
And use this in my XXX.html.twig
{{ render(controller('App\\Controller\\DetailsController:credits')) }}
I have been working with symfony for 4 weeks now so not that long.
I want to call some functions when the form is submitted only nothing that I place in the if statement is working, it doesn't throw any exception at the moment. Am I not seeing something or is it not possible to do this when I render a form?
EDIT:
my credits_widget.html.twig
{% block credits %}
{{ form_start(form.credits) }}
{{ form_widget(form.credits) }}
{% if app.user %}
<button type="submit">Koop nu!</button>
{% else %}
<button type="button">Login en koop</button>
<button type="button">Registreer en koop</button>
{% endif %}
{{ form_end(form.credits) }}
{% endblock %}
The problem is that the form is rendered without action and when submitted, it is submitted by default to the root route from which it was rendered. So the credits action is not being called. You should change the action of the form like this:
public function credits(Request $request)
{
// set current url path as form's action
$form = $this->createForm(CreditType::class, null, , [
'action' => $request->getRequestUri()
]);
$form->handleRequest($request);
if ($form->isSubmitted()) {
throw new \Exception('It works!');
}
return $this->render(
'credits/credits_widget.html.twig',
[
'form' => $form->createView(),
]
);
}
EDIT: You are currently rendering subform form.credits when you should really render form as it is passed from your controller. Your credits_widget.html.twig template should look like this:
{% block credits %}
{{ form_start(form) }}
{{ form_widget(form) }}
{% if app.user %}
<button type="submit">Koop nu!</button>
{% else %}
<button type="button">Login en koop</button>
<button type="button">Registreer en koop</button>
{% endif %}
{{ form_end(form) }}
{% endblock %}
I am still new to Symfony and Php, so I am using the CheckboxType code from Symfony docs.
Currently no message is appearing if a user attempts to register and the checkbox is unchecked, but it will still prevent the user from making a account.
(1) I would like a error message to appear next to the checkbox in red stating the box must be checked in order to proceed. I would also like to customize this message.
Thank you!
Register.html
{% extends 'base.html.twig' %}
{% block body %}
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>Register!</h1>
{{ form_start(form) }}
{{ form_row(form.username) }}
{{ form_row(form.email) }}
{{ form_row(form.plainPassword.first, {
'label': 'Password'
}) }}
{{ form_row(form.plainPassword.second, {
'label': 'Repeat Password'
}) }}
Terms of service
{{ form_widget(form.termsAccepted) }}
cancel
<button type="submit" class="btn btn-primary" formnovalidate>
Register
</button>
<br></br>
<p>Privacy Policy
{{ form_end(form) }}
</div>
</div>
</div>
{% endblock %}
RegistrationForm.php
class UserRegistrationForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class)
->add('username', TextType::class)
->add('plainPassword', RepeatedType::class, ['type' => PasswordType::class])
->add('termsAccepted', CheckboxType::class, array(
'mapped' => false,
'constraints' => new IsTrue(),));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
'validation_groups' => ['Default', 'Registration']
]);
}
}
The problem is that you are using:
{{ form_widget(form.termsAccepted) }}
for rendering the checkbox. This will only render the widget, whereas:
{{ form_row(form.termsAccepted) }}
as is used by all the user fields would contain the label, the widget and the error message. If you want to keep the widget, e.g. because using form_row messes up the template somehow you could render the errors individually using:
{{ form_errors(form.termsAccepted) }}
You might also want to check out the documentation on Form Customization.
Is there any possibility in symfony2 to display a readonly-field of an entity as a label rather than a text field or whatever?
I am currently using the following code, but using a disabled text field does not feel very sophisticated:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('readonlyfield', 'text', array('property_path' => 'readonlyfield.displayString','disabled' => true));
$builder->add('editablefield', 'textarea');
}
I am using symfony 2.4.4..
EDIT:
I am using this form type from within another form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('mySubEntities', 'collection', array('type' => new MySubEntryType()));
$builder->add('save_to_db', 'submit', array('label' => 'Submit'));
}
twig file:
{{ form_start(form) }}
{% for row in form.mySubEntities %}
<li>
<ul>
<table>
<tr><td>{{ form_label(row.readonlyfield) }} </td><td>{{ form_widget(row.readonlyfield) }}</td></tr>
<tr><td>{{ form_label(row.editablefield) }}</td><td> {{ form_widget(row.editablefield) }}</td></tr>
</table>
</ul>
</li>
{% endfor %}
{{ form_end(form) }}
You can access value in form using {{ form.vars.value.yourfield }}.
You have a nested/collection so use {{ row.vars.value.yourfield }}
Why don't you just render the entity property in your template instead of making it part of a form? You could make your own FieldType but that's not what I recommand. If you want the value to be displayed as a form like file I would use the readonly property.