How to control marked checkbox order in twig - php

So I'm facing this weird behavior when listing a series of checkboxes with twig
see the new page, it displays everything right, and saying that i'm saving this laboratory
img1
ok, I saved the laboratory, now went to the edit page
img2
the marked checkboxes displays at first, ruining the alphabetic order that was at the new page.
I need that the edit page become exactly like the new page, but I don't know how to organize these checkboxes on twig.
block that renders the checkboxes:
{% block _appbundle_laboratory_laboratoryExams_row %}
<div class="form-group">
{{ form_label(form) }}
<div class="col-md-10 col-md-offset-2">
<div class="app-checkbox-collection">
<p>{{ 'laboratory.field_laboratory' | trans }}</p>
{% dump(form) %}
{% for child in form %}
{% if child.exam.vars.data.type == constant('AppBundle\\Entity\\ExamLaboratory::TYPE')%}
{{ form_widget(child.permission, {
'attr' : {
'class' : 'exam-checkbox'
},
'label' : child.exam.vars.data.name
}) }}
{% endif %}
{% endfor %}
<p>{{ 'laboratory.field_image' | trans }}</p>
{% for child in form %}
{% if child.exam.vars.data.type == constant('AppBundle\\Entity\\ExamImage::TYPE')%}
{{ form_widget(child.permission, {
'attr' : {
'class' : 'exam-checkbox'
},
'label' : child.exam.vars.data.name
}) }}
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
I don't ask at portuguese stackoverflow because no one answers symfony questions there, few users probably
EDIT:
Here is the buildForms:
Laboratory
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, array(
'label' => 'laboratory.name',
'attr' => array('class' => 'focus')
))
->add('leader', null, array(
'label' => 'laboratory.leader'
))
->add('city', null, array(
'label' => 'laboratory.city',
'placeholder' => 'action.select_one'
))
->add('laboratoryExams', 'collection', array(
'label' => 'laboratory.laboratoryExams',
'type' => new LaboratoryExamType(),
'allow_delete' => true,
'by_reference' => false,
))
;
}
LaboratoryExam
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('permission', null, array(
'label' => 'laboratoryexam.permission',
))
->add('exam', null, array(
'label' => 'laboratoryexam.exam',
))
;
}

You can set the order of checkboxes while building the form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('permission', 'entity', [
'class' => 'Acme\AppBundle\Entity\Parameter',
'multiple' => true,
'expanded' => true,
'query_builder'=> function(EntityRepository $repository) {
return $repository->createQueryBuilder('exam')->orderBy('exam.title', 'ASC');
},
]);
}

I would say it has nothing to do with twig.
That would be set on the form type object where the form with checkboxes is constructed.
It seems the data is populated programmatically on form creation with already selected choices being first.
If it isn't the case or you got some problem, please edit your question with formtype code and code where you get the data for the checkboxes.

thanks for the answers, i found a solution by resorting the ArrayCollection in the form.
$iterator = $form->get('laboratoryExams')->getData()->getIterator();
$iterator->uasort(function ($a, $b) {
return ($a->getExam()->getName() < $b->getExam()->getName()) ? -1 : 1;
});
$form->get('laboratoryExams')->setData(new ArrayCollection(iterator_to_array($iterator)));
IMO this should be done by default, I believe that no one would like to have the check-boxes disordered that way

Related

Symfony - How to show a collection of form inputs with a loop in a twig template?

I'm a beginner with PHP and Symfony.
I'm trying to show each values of ring (which is entity) from database and trying to add checkbox at the end of the each ring.
My twig template only shows the checkbox in the first ring.
How do I show all the rings?
This is my controller:
public function testPage(Request $request) {
$ring = $this->ringRepository->customFindAll();
$jewel = $this->ringJewelRepository->customFindAll();
$custom = $this->customRingRepository->customFindAll();
$form = $this->createFormBuilder($ring)
->add('active', CheckboxType::class, [
'label'=>'Selection',
'required'=>false
])
->getForm();
$form->handleRequest($request);
return [
'rings'=>$ring,
'jewels'=>$jewel,
'custom' => $custom,
'form'=>$form->createView()
];
}
This is my Twig template:
{% for ring in rings %}
<div>
<div class="text-center">
<p>Ring Name: {{ ring.ring_name }}</p>
<p>Ring Type: {{ ring.ring_type }}</p>
{{ form_start(form) }}
{{ form_widget(form.active) }}
{{ form_end(form) }}
</div>
<div class="text-center">
Update Ring
</div>
</div>
{% endfor %}
Considering your use-case I think you might be looking for an EntityType, with the 'multiple' option set to true. The syntax would be as below. Make sure to import your Ring class as well.
->add('active', EntityType::class, [
'class' => Ring::class,
'multiple' => true,
'label' => 'Selection',
'required' => false,
'query_builder' => static fn (RingRepository $ringRepository) => $ringRepository->customFindAll(),
]);
You can read more about the EntityType in the symfony docs.

Align multiple form inputs horizontally

I have a form with a collectionType field, this field has 3 inputs and I want to align all 3 of them horizontally. Is it possible to do that in Symfony?
Also: Is it possible to choose the label for each element inside the collectionType?
Here's my form:
class WorkerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Firstname')
->add('Lastname')
->add('tasks', CollectionType::class, [
'label' => 'Tasks',
'entry_type' => TasksType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'required' => false,
'by_reference' => false,
'delete_empty' => true,
'attr' => [
'class' => 'collection',
],
])
;
$builder->add('save', SubmitType::class, [
'label' => 'Valider',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => worker::class,
]);
}
}
Here's my tasks form:
class TasksType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label')
->add('start')
->add('end')
;
}
and here's my _form.html.twig:
{% block extra_js %}
<script src="{{ asset('jquery.collection.js') }}"></script>
{% endblock %}
{% block body %}
<div class="row">
{%
form_theme form
'jquery.collection.html.twig'
'TaksTemplate.html.twig'
%}
{{ form_start(form) }}
<div class="my-custom-class-for-errors">
{{ form_errors(form) }}
</div>
<div class="col">
{{ form_row(form.Firstname, {'label': 'firstname'}) }}
</div>
<div class="col" >
{{ form_row(form.Lastname, {'label': 'Lastname'}) }}
</div>
<div class="col">
{{ form_row(form.tasks, {'label': 'tasks'}) }}
</div>
</div>
{{ form_end(form) }} </div>
{% endblock %}
{% block script %}
<script type="text/javascript">
$('.collection').collection({
'drag_drop_options': {
'placeholder': null
}
});
</script>
{% endblock %}
Also: is is possible to choose the label for each element inside the collectionType ?
No. you can't have multiple label in symfony collectionType.
I want to align all 3 of them horizontally.
Ask this again with HTML CSS tags

How to keep form data when browsing paginated output?

I have a symfony form that contains a long list of items with checkboxes. I have successfully made knp paginator work and now the form is split into pages. However, when I move between pages I lose the checked/unchecked status of the checkboxes. I am sure that this is probably quite easy but I cannot seem to work it out. I am not very experienced with php yet.
Here is my controller:
/**
* #Route("/addquestions/{quizid}", name="addquestions")
*/
public function add(Request $request, PaginatorInterface $paginator, $quizid)
{
$repository = $this->getDoctrine()->getRepository(Quiz::class);
$quiz = $repository->find($quizid);
$repository = $this->getDoctrine()->getRepository(Question::class);
$questions = $repository->findAll();
// Paginate the results of the query
$pagination = $paginator->paginate($questions, $request->query->getInt('page', 1), 3);
$form = $this->createForm(AddQuizQuestionType::class, $quiz, ["pagination" => $pagination]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$questions = $form->get('question')->getData();
foreach ($questions as $question){
$quizquestion = new QuizQuestion();
$quizquestion->setQuestion($question);
$quiz->addQuizQuestion($quizquestion);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($quiz);
$entityManager->flush();
return $this->redirectToRoute('homepage');
}
return $this->render('editquiz/addquestions.html.twig', [
'form' => $form->createView(),
'pagination' => $pagination,
]);
}
And my form - it uses the paginated query to display the items with a check box.
class AddQuizQuestionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('question', EntityType::class, [
'expanded' => true,
'multiple' => true,
'class' => Question::class,
'mapped' => false,
'choices' => $options['pagination'],
])
->add('submit', SubmitType::class, [
'label' => 'Submit',
])
->setMethod('GET')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Quiz::class,
'pagination' => null,
]);
}
}
and my template - it renders the checkboxes with images from the database.
{% extends 'base.html.twig' %}
{% block title %}CreatequizController{% endblock %}
{% block body %}
<h1>Create Quiz</h1>
{{ form_start(form) }}
{% for question in form.question %}
<h5>Question {{ question.vars.value }}</h5>
<div class="border mb-5">
<img src="{{ asset(question.vars.label) }}" alt=""/>
<div class="pl-3">
{{ form_widget(question) }}
</div>
</div>
{% endfor %}
<div class="navigation">{{ knp_pagination_render(pagination) }}</div>
{{ form_end(form) }}
{% endblock %}
I would like it so that when I jump between pages the checkboxes that I have selected remain checked.
Thank you in advance,
Martyn

Symfony transform ChoiceType in CheckboxType

I've problem with my form type. I have an entity activity and an other entity class. It's in ManyToMany. When I display the form, it's in ChoiceType, but I want it to be in CheckboxType. So I've :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('libelle')
->add('horraire')
->add('horraireDebut')
->add('horraireFin')
->add('description')
->add('classes');
}
It display a ChoiceType but I want a CheckboxType, so I changed this to :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('libelle')
->add('horraire')
->add('horraireDebut')
->add('horraireFin')
->add('description')
->add('classes', CheckboxType::class);
}
But this only displays one checkbox while I have several recordings (which appears well with the first code).
My form.html.twig :
<div class="form-group{% if form.classes.vars.errors|length %} has-error{% endif %}">
<label for="{{ form.classes.vars.id }}" class="col-sm-3 control-label no-padding-right required">Classes <span class="red">*</span></label>
<div class="col-sm-9">
{{ form_widget(form.classes,{'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.classes) }}
</div>
How can I get a checkbox line or a checkbox dropdown ?
Thanks!
Just use multiple and expanded options together to achieve this (Ref):
$builder->add('classes', null, array(
'multiple' => true,
'expanded' => true,
));
Then checkboxes will be rendered.
Note that null value mean EntityType::class in case you use Doctrine ORM. Otherwise, use EntityType::class and 'class' => Entity::class option.
In order to achieve what you're looking for, you could also try the EntityType with a query builder:
->add('classes', EntityType::class, array(
'by_reference' => true,
'multiple' => true,
'expanded' => false,
'class' => 'AppBundle\Entity\Class',
'property' => 'name',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
$qb = $er->createQueryBuilder('c');
return $qb->orderBy('c.name', 'ASC');
}
))

Symfony2 multiple Entities of same class in one Form

I want to render a form which has multiple Entities of same Class.
I will display 2 fields, Price(type=text) and Enabled(type=checkbox).
I don't know how many I will have of those entities, so form will have to get them dynamically.
I have tried to do the following
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('price', 'text', array(
'label' => 'Price',
'required' => true
))
->add('enabled','checkbox',array(
'label' => 'Use this currency',
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Osiris\Entity\Pricing',
'csrf_protection' => false
));
}
public function getName()
{
return 'pricingtype';
}
And in my Controller I have created my form like this:
$pricingForm = $this->createFormBuilder($prices)
->add('items','collection',array(
'required' => false,
'prototype' => true,
'type' => new PricingType(),
))
->getForm()
;
In my twig I do:
{% for price in form_pricing %}
<h2>Price</h2>
<div class="row">{{ form_widget(price) }}</div>
{% endfor %}
However it comes only with h2 Prices and empty div with class=row. I feel like I am half way there, but I've no idea how to move on.
If someone knows how to get fields on submit as well, I will really appreciate it.
I found the solution,
the way I was creating the form in Controller was wrong!
I had to do the following:
$pricingForm = $this->createFormBuilder(array('prices'=>$prices))
->add('prices','collection',array(
'required' => true,
'allow_add' => true,
'type' => new PricingType(),
))
->getForm()
;
"allow_add => true" is necessary when working with collection, otherwise it will NOT add any of PricingType collection of entities to the form.
Then, because the form is built inside the controller "$this->createFormBuilder(array('prices'=>$prices))" , $prices array must be passed as an array with array keyname same as the one used in "->add('prices','collection',array(...)" , which is 'prices' so Symfony will know what to bind where. $prices is an array of Pricing objects array(0 => new Pricing()).
In my PricingType I have:
class PricingType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('price', 'text', array(
'label' => false,
'required' => true
))
->add('enabled','checkbox',array(
'label' => 'Use this currency',
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'XXX\XXX\Entity\Pricing',
'csrf_protection' => false
));
}
public function getName()
{
return 'pricingtype';
}
}
Here I need to have control over label attribute. I could not find the way for it( if anyone knows please post how to). I override my twig template as follows:
On the top we need next line of code:
{% form_theme form_pricing _self %}
Then override row and widget as follows (it was a nightmare to debug):
{% block _form_prices_entry_row %}
{% spaceless %}
{{ form_widget(form) }}
{% endspaceless %}
{% endblock %}
{% block _form_prices_entry_widget %}
{% spaceless %}
{{ form_row(form.price, { 'label' : form.vars.value.getCurrency().getTitle() } ) }}
{{ form_row(form.enabled) }}
{% endspaceless %}
{% endblock %}
In the body then, render form elements as follows:
{% for price in form_pricing.prices %}
<div class="price-row">{{ form_row(price) }}</div>
{% endfor %}
I really hope this will help you guyz. It was a real nightmare to debug especially the twig file, I did it thanks to my clever colleague.
I think you have missed a for loop in your twig file
Check this example:
{# store the prototype on the data-prototype attribute #}
<ul id="email-fields-list" data-prototype="{{ form_widget(form.emails.vars.prototype)|e }}">
{% for emailField in form.emails %}
<li>
{{ form_errors(emailField) }}
{{ form_widget(emailField) }}
</li>
{% endfor %}
</ul>
See the loop, I think that you need to add in your twig file.
In addition to loops you need to add JavaScript also.
Check this link:
http://symfony.com/doc/current/reference/forms/types/collection.html#adding-and-removing-items
Check the complete code. It will help you out to generate multiple entity forms from a single entity class using collection field type.

Categories