Buscar..
Cómo extender ChoiceType, EntityType y DocumentType para cargar opciones con AJAX.
En Symfony, el ChoiceType integrado (y EntityType o DocumentType que lo extiende), funciona básicamente con una lista de opciones constante.
Si desea que funcione con llamadas ajax, debe cambiarlas para que acepte cualquier opción adicional resumida.
¿Cómo empezar con una lista de opciones vacía?
Cuando cree su formulario, simplemente configure la opción de
choices
en unaarray()
vacíaarray()
:namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('tag', ChoiceType::class, array('choices'=>array())); } }
Así obtendrá una entrada de selección vacía, sin opciones. Esta solución funciona para ChoiceType y todos sus hijos (EntityType, DocumentType, ...).
Cómo aceptar nuevas opciones enviadas :
Para aceptar las nuevas opciones, debe hacer que estén disponibles en la lista de selección de campos de formulario. Puede cambiar el campo de formulario según los datos enviados con el evento FormEvent :: PRE_SUBMIT.
Este ejemplo muestra cómo hacerlo con un ChoiceType básico:
namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('tag', ChoiceType::class, array('choices'=>array())) ; $builder->addEventListener( FormEvents::PRE_SUBMIT, function(FormEvent $event){ // Get the parent form $form = $event->getForm(); // Get the data for the choice field $data = $event->getData()['tag']; // Collect the new choices $choices = array(); if(is_array($data)){ foreach($data as $choice){ $choices[$choice] = $choice; } } else{ $choices[$data] = $data; } // Add the field again, with the new choices : $form->add('tag', ChoiceType::class, array('choices'=>$choices)); } ); } }
Tus opciones enviadas ahora son opciones permitidas y la validación integrada de Symfony ChoiceType no las rechazará más.
Si desea hacer lo mismo con un hijo ChoiceType (EntityType, DocumentType, ...), debe inyectar el entityManager o el documentManager y realizar la transformación de datos al completar las nuevas opciones.
Rellene un campo de selección en función del valor de otro.
Este es un ejemplo para mostrar cómo cambiar las opciones permitidas en un campo de selección de subcategoría dependiendo del valor del campo de selección de categoría. Para hacer esto, tiene que hacer que sus elecciones de subcategoría sean dinámicas tanto para el cliente como para el servidor.
1. Haga que el formulario sea dinámico en el lado del cliente para las interacciones entre la pantalla y el usuario.
Ejemplo de forma dinámica del lado del cliente (usando Javascript / JQuery):
$('#category').change(function(){
switch($(this).val()){
case '1': // If category == '1'
var choice = {
'choice1_1':'1_1',
'choice1_2':'1_2',
'choice1_3':'1_3',
};
break;
case '2': // If category == '2'
var choice = {
'choice2_1':'2_1',
'choice2_2':'2_2',
'choice2_3':'2_3',
};
break;
case '3': // If category == '3'
var choice = {
'choice3_1':'3_1',
'choice3_2':'3_2',
'choice3_3':'3_3',
};
break;
}
var $subCategorySelect = $('#subCategory');
$subCategorySelect.empty();
$.each(choice, function(key, value) {
$subCategorySelect.append($('<option></option>')).attr('value',value).text(key);
});
});
Por supuesto, usted podría obtener las opciones de una llamada AJAX. Ese no es el propósito de este ejemplo.
2. Haga el formulario dinámico en el lado del servidor para la inicialización / validación
Ejemplo de forma dinámica del lado del servidor:
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class MyBaseFormType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category',ChoiceType::class,array('choices'=>array(
'choice1'=>'1',
'choice2'=>'2',
'choice3'=>'3',
)))
;
$addSubCategoryListener = function(FormEvent $event){
$form = $event->getForm();
$data = $event->getData();
switch($data['category']){
case '1': // If category == '1'
$choices = array(
'choice1_1'=>'1_1',
'choice1_2'=>'1_2',
'choice1_3'=>'1_3',
);
break;
case '2': // If category == '2'
$choices = array(
'choice2_1'=>'2_1',
'choice2_2'=>'2_2',
'choice2_3'=>'2_3',
);
break;
case '3': // If category == '3'
$choices = array(
'choice3_1'=>'3_1',
'choice3_2'=>'3_2',
'choice3_3'=>'3_3',
);
break;
}
$form->add('subCategory',ChoiceType::class,array('choices'=>$choices));
};
// This listener will adapt the form with the data passed to the form during construction :
$builder->addEventListener(FormEvents::PRE_SET_DATA, $addSubCategoryListener);
// This listener will adapt the form with the submitted data :
$builder->addEventListener(FormEvents::PRE_SUBMIT, $addSubCategoryListener);
}
}