Symfony2: changer les choix avec ajax et validation
scénario: j'ai une forme avec 2 sélections. Lorsque l'utilisateur sélectionne quelque chose à partir du premier select, le second select est rempli de nouvelles valeurs. Cette partie fonctionne très bien.
mais le formulaire n'est pas validé car il contient des choix qui ne sont pas autorisés dans le formulaire initial.
Forme:
<?php
class MyType extends AbstractType
{
private $category;
public function __construct($category = null)
{
$this->category = $category;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', 'choice', array(
'choices' => array(
'foo' => 'foo',
'bar' => 'bar'
)
);
$builder->add('template', 'choice', array(
'choices' => $this->loadChoices()
);
}
private function loadChoices()
{
// load them from DB depending on the $this->category
}
}
initialement la catégorie est foo
. Ainsi, les modèles pour foo sont chargés et définis comme des choix. Mais si l'utilisateur sélectionne bar
, les modèles de barres obtiennent charger. Mais le formulaire a toujours les choix foo et ne valide pas.
Quelle est la meilleure façon de résoudre ce problème?
une façon que j'ai trouvée était de simplement réinitialiser la forme dans le contrôleur:
<?php
$form = $this->createForm(new MyType());
if ($request->getMethod() === 'POST') {
if ($request->request->has($form->getName())
&& isset($request->request->get($form->getName())['category'])) {
$form = $this->createForm(new MyType($request->request->get($form->getName())['category']));
}
// ...
}
cela fonctionne, mais je ne peux pas le tester parce qu'il jette IllegalArgumentException
lors de la définition de la valeur et suppose simplement par défaut. Est-il une meilleure solution? Merci à l'avance!
1 réponses
je pense que u ont pour utiliser les Événements pour gérer ce qui est plus correct
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', 'choice', array(
'choices' => array(
'foo' => 'foo',
'bar' => 'bar'
)
));
$ff = $builder->getFormFactory();
// function to add 'template' choice field dynamically
$func = function (FormEvent $e) use ($ff) {
$data = $e->getData();
$form = $e->getForm();
if ($form->has('template')) {
$form->remove('template');
}
$cat = isset($data['category'])?$data['category']:null;
// here u can populate ur choices in a manner u do it in loadChoices
$choices = array('1' => '1', '2' => '2');
if ($cat == 'bar') {
$choices = array('3' => '3', '4' => '4');
}
$form->add($ff->createNamed('template', 'choice', null, compact('choices')));
};
// Register the function above as EventListener on PreSet and PreBind
$builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
$builder->addEventListener(FormEvents::PRE_BIND, $func);
}