Validar opciones cargadas dinĂ¡micamente en Symfony 2
validation symfony-2.1 (5)
Tengo un tipo de campo de elección llamado * sub_choice * en mi formulario cuyas elecciones se cargarán dinámicamente a través de AJAX dependiendo del valor seleccionado del campo de elección principal, llamado * parent_choice *. La carga de las opciones funciona a la perfección, pero tengo un problema al validar el valor de sub_choice al enviarlo. Da un error de validación "Este valor no es válido" ya que el valor enviado no está en las opciones del campo sub_choice cuando se construyó. Entonces, ¿hay alguna manera de validar correctamente el valor enviado del campo sub_choice? Abajo está el código para construir mi formulario. Estoy usando Symfony 2.1.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(''parent_choice'', ''entity'', array(
''label'' => ''Parent Choice'',
''class'' => ''Acme/TestBundle/Entity/ParentChoice''
));
$builder->add(''sub_choice'', ''choice'', array(
''label'' => ''Sub Choice'',
''choices'' => array(),
''virtual'' => true
));
}
Agregando un enfoque alternativo para futuros lectores ya que tuve que hacer mucha investigación para que mi formulario funcionara. Aquí está el desglose:
- Agregar una opción "Nueva" a un menú desplegable a través de jQuery
- Si se selecciona "Nuevo", se mostrará el nuevo campo de formulario "Opción personalizada"
- Enviar formulario
- Validar datos
- Guardar en la base de datos
código jquery para ramita:
$(function(){
$(document).ready(function() {
$("[name*=''[custom_option]'']").parent().parent().hide(); // hide on load
$("[name*=''[options]'']").append(''<option value="new">New</option>''); // add "New" option
$("[name*=''[options]'']").trigger("chosen:updated");
});
$("[name*=''[options]'']").change(function() {
var companyGroup = $("[name*=''[options]'']").val();
if (companyGroup == ''new'') { // when new option is selected display text box to enter custom option
$("[name*=''[custom_option]'']").parent().parent().show();
} else {
$("[name*=''[custom_option]'']").parent().parent().hide();
}
});
});
// Here''s my Symfony 2.6 form code:
->add(''options'', ''entity'', [
''class'' => ''Acme/TestBundle/Entity/Options'',
''property'' => ''display'',
''empty_value'' => ''Select an Option'',
''mapped'' => true,
''property_path'' => ''options.optionGroup'',
''required'' => true,
])
->add(''custom_option'', ''text'', [
''required'' => false,
''mapped'' => false,
])
Para manejar los datos del formulario necesitamos usar el evento de formulario PRE_SUBMIT.
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (isset($data[''options'']) && $data[''options''] === ''new'') {
$customOption = $data[''custom_option''];
// todo: handle this better on your own
if (empty($customOption)) {
$form->addError(new FormError(''Please provide a custom option''));
return;
}
// Check for a duplicate option
$matches = $this->doctrine->getRepository(''Acme/TestBundle/Entity/Options'')->matchByName([$customOption]);
if (count($matches) > 0) {
$form->addError(new FormError(''Duplicate option found''));
return;
}
// More validation can be added here
// Creates new option in DB
$newOption = $this->optionsService->createOption($customOption); // return object after persist and flush in service
$data[''options''] = $newOption->getOptionId();
$event->setData($data);
}
});
Avísame si tienes alguna pregunta o inquietud. Sé que esta podría no ser la mejor solución pero funciona. ¡Gracias!
Para hacer el truco, debe sobrescribir el campo sub_choice
antes de enviar el formulario:
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$parentChoice = $event->getData();
$subChoices = $this->getValidChoicesFor($parentChoice);
$event->getForm()->add(''sub_choice'', ''choice'', [
''label'' => ''Sub Choice'',
''choices'' => $subChoices,
]);
});
}
Supongamos que para las elecciones secundarias tienes el derecho de identificación? Crea y vacía una matriz con un cierto número de valores y dale como opción
$indexedArray = []; for ($i=0; $i<999; $i++){ $indexedArray[$i]= ''''; }
entonces ''choices'' => $indexedArray,
:)
esto acepta cualquier valor
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
if(is_array($data[''tags'']))$data=array_flip($data[''tags'']);
else $data = array();
$event->getForm()->add(''tags'', ''tag'', [
''label'' => ''Sub Choice'',
''choices'' => $data,
''mapped''=>false,
''required''=>false,
''multiple''=>true,
]);
});
no puede no crear la validación de sub_choice porque durante su configuración de su validador no sabe qué valores son válidos (los valores dependen del valor de parent_choice).
Lo que puede hacer es resolver parent_choice en entidad antes de crear un nuevo YourFormType () en su controlador. Luego, puede obtener todos los valores posibles para sub_choice y proporcionarlos a través del constructor de formularios: nuevo YourFormType ($ subChoice).
En YourFormType tienes que agregar el método __construct como este:
/**
* @var array
*/
protected $subChoice = array();
public function __construct(array $subChoice)
{
$this->subChoice = $subChoice;
}
y usar los valores proporcionados en forma agregar:
$builder->add(''sub_choice'', ''choice'', array(
''label'' => ''Sub Choice'',
''choices'' => $this->subChoice,
''virtual'' => true
));