Symfony 6 set default value for unmapped ChoiceType field in form

183 views Asked by At

I have this scenario:

A value is read from a cookie and passed as an $option to a FormType:

$indexOrder = $request->cookies->get('clientfile-order') ?? 'date-last';
$advancedSearchform = $this->createForm(ClientFileSearchType::class, null, ['index_order' => $indexOrder]);

Inside the Form I have this code:

$builder
        ->add('queryOrder', ChoiceType::class, ['label'     => "Order by",
                                                'mapped'   => false, 
                                                'expanded' => false,
                                                'multiple' => false,
                                                'required' => true,
                                                //'empty_data' => $options['index_order'],
                                                'data'     => $options['index_order'],
                                                'choices'  => [ 'Fecha de última actuación'              => 'action-last',
                                                                'Fecha apertura (más recientes primero)' => 'date-last',
                                                                'Fecha apertura (más antiguos primero)'  => 'date-first',
                                                                'Nº fichero (más recientes primero)'  => 'clientfile-last',
                                                                'Nº fichero (más antiguos primero)'   => 'clientfile-first'
                                                                ]
                                                ]);

public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'index_order'   => null, //'date-last',
        'data_class'    => null,
    ]);
}

If I debug $indexOrder value after cookie reading, the value is correct before passing option to createForm. I tried both attributes data and empty_data and both of them behave the same.

But default value is not loaded, it always shows last value used in previous call and only if I reload page with Ctrl + F5 the correct value appears.

I could set the value by Javascript but if possible I prefer set it on server, is there a way to do that? What is failing?

1

There are 1 answers

0
pok_net On

it is probably the way you pass index_order in $options.

you should probably just try to debug indexOrder inside the form type.

you might also add a model for better control over the form variables.

here is a working example using the main form from the symfony docs with addition of your drop down box:

TaskModel.php

namespace App\Model;
use DateTimeInterface;

class TaskModel
{
    protected string $name;

    protected ?DateTimeInterface $dueDate;

    protected string $indexOrder;

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function getDueDate(): ?DateTimeInterface
    {
        return $this->dueDate;
    }

    public function setDueDate(?DateTimeInterface $dueDate): void
    {
        $this->dueDate = $dueDate;
    }

    public function getIndexOrder(): string
    {
        return $this->indexOrder;
    }

    public function setIndexOrder(string $indexOrder): void
    {
        $this->indexOrder = $indexOrder;
    }
}

pageController.php

    #[Route('/page3', name: 'page3')]
    public function page3(Request $request): Response
    {
        $indexOrder = $request->cookies->get('clientfile-order') ?? 'date-last';
        $task = new TaskModel();
        $task->setName('Write a blog post');
        $task->setDueDate(new DateTimeImmutable('tomorrow'));
        $task->setIndexOrder($indexOrder);
        $form = $this->createForm(TaskType::class, $task);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $task2 = $form->getData();
        }
        return $this->render('page/page3.html.twig', [
            'form' => $form,
        ]);
    }

TaskType.php


class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        //dd($options);
        $data1 = $options['data']->getIndexOrder();

        $builder
            ->add('name', TextType::class)
            ->add('dueDate', DateType::class)
            ->add('queryOrder', ChoiceType::class, ['label'     => "Order by",
                'mapped'   => false,
                'expanded' => false,
                'multiple' => false,
                'required' => true,
                //'empty_data' => $options['index_order'],
                'data'     => $data1,
                'choices'  => [ 'Fecha de última actuación'     => 'action-last',
                    'Fecha apertura (más recientes primero)'    => 'date-last',
                    'Fecha apertura (más antiguos primero)'     => 'date-first',
                    'Nº fichero (más recientes primero)'        => 'clientfile-last',
                    'Nº fichero (más antiguos primero)'         => 'clientfile-first'
                ]
            ])

            ->add('save', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => TaskModel::class,
        ]);
    }
}

and finally in the twig template just add {{ form(form) }} or any other customisation if needed.