Issue
I want to build a custom AjaxEntityType that loads the options over ajax. I cannot build the form with all the choices because there are too many and the performance is greatly affected.
The problem is that if I readd the form field (like in the cookbook) from within the custom type the data doesn't get submitted at all.
I need a way to change the choices from within the Custom Type Class without readding the form field.
Here is my class:
<?php
namespace App\Form\Type;
class AjaxEntityType extends AbstractType
{
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'ajax_url' => null
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
$data = $event->getData();
if ($data === null || $data === []) {
return;
}
// here i get the ids from the submited data, get the entities from the database and I try to set them as choices
$entityIds = is_array($data) ? $data : [$data];
$entities = $this->em->getRepository($event->getForm()->getConfig()->getOptions()['class'])->findBy(["id" => $entityIds]);
$options['choices'] = $entities;
$event->getForm()->getParent()->add(
$event->getForm()->getName(),
self::class,
$options
);
// the result is that the from gets submitted, but the new data is not set on the form. It's like the form field never existed in the first place.
});
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['ajax_url'] = $options['ajax_url'];
}
public function getParent()
{
return EntityType::class;
}
}
My controller is as simple as it gets:
public function create(Request $request, ProductService $productService, Product $product = null)
{
if(empty($product)){
$product = new Product();
}
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->persist($product);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('products_list');
}
return $this->render('admin/products/form.html.twig', [
'page_title' => "Product form",
'product' => $product,
'form' => $form->createView()
]);
}
Solution
Altering the form in the PRE_SET_DATA (to keep the selected choices in the form) and in the PRE_SUBMIT (to add the newly selected items to the choice list) ended up being a huge headache. Always needed some adjustments with a lot of complications.
So as a final solution I removed all the choices in the buildView method of my custom type class, it works well.
// in file App\Form\Type\AjaxEntityType.php
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['ajax_url'] = $options['ajax_url'];
// in case it's not a multiple select
if(!is_array($view->vars['value'])){
$selected = [$view->vars['value']];
}else{
$selected = $view->vars['value'];
}
foreach($view->vars['choices'] as $index => $choice){
if(!in_array($choice->value, $selected)){
unset($view->vars['choices'][$index]);
}
}
}
Answered By - Vlad Dogarescu
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.