I have a Symfony3 form that has a ChoiceType field. It uses Select2 with an AJAX data source. This bit is working fine. However, when the form is submitted, the Symfony validation kicks in and complains:
This value is not valid
I guess this is because the choice picked via AJAX doesn't exist in the 'choices' key in the Form Type.
I'm relatively new to Symfony. Can someone point me in the right direction to disable the validation on the field?
You shouldn't disable validation. Add choices dynamically with Form Events
- http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html
You can also take a look at this bundle: https://github.com/tetranz/select2entity-bundle
You must always use a string value to submit data to a ChoiceType
.
Considering the following ChoiceType
configuration:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
$builder->add('some_choice', ChoiceType::class, array(
'choices' => array(
'Choose 1' => 1,
'Choose A' => 'A',
'Choose True' => true,
),
));
By default, you might expect every key from the choice array to be used as label, and and every choice value to be converted to string and used as html value:
<option value="1">Choose 1</option>
<option value="A">Choose A</option>
<option value="1">Choose True</option>
This example above is wrong.
As you can see, casting true
to string gives "1"
and it's already used for integer 1 choice.
All choice values MUST always be unique, so instead by default, in that case, the ChoiceType
uses a numeric incrementation:
<option value="0">Choose 1</option>
<option value="1">Choose A</option>
<option value="2">Choose True</option>
The same happens when some model choice value in the choice array are not scalar (e.g array
, object
, null
...).
Then the submitted data should be "0"
, "1"
or "2"
. Each will be mapped backed to the corresponding choice by the ChoiceType
.
To keep the full control of the string value to use for each choice, you can use the option choice_value
as a closure which gets passed each choice as only argument and must return its string value.
If your choices are objects or arrays you can set it as a property path:
'choice_value' => 'property'
// will be equivalent to
'choice_value' => function ($choice) {
if (is_array($choice)) {
return $choice['property'];
}
if (is_object($choice)) {
return $choice->getProperty();
// or even $choice->isProperty()
}
throw new UnexpectedTypeException();
}
Default behavior is same as:
$builder->add('some_choice', ChoiceType::class, array(
'choices' => array(
'Choose 1' => 1,
'Choose A' => 'A',
'Choose True' => true,
),
'choice_value' => function ($choice) {
if (!is_scalar($choice) {
return null;
}
return false === $choice ? '0' : (string) $choice;
},
));
If null
or two identical values are returned, an incrementing integer will be used instead.
You always have to submit the string choice value in order to get it mapped back by the ChoiceType
.
Any unknown values or "extra" values will end up with your error.
See the official doc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With