问题
When I send a form with an unchecked checkbox, if the related entity property equals true
, then it does not change to false
.
The other way round (setting property to true when the form is sent with a checked checkbox) works fine, as well as all the forms other fields saving.
Here is how I build the form and declare the related property:
// --- Form creation function EntityType::buildForm() ---
$builder->add('secret', 'checkbox', array( 'required' => false ));
// --- Entity related property, Entity.php file ---
/** @ORM\Column(name="secret", type="boolean") */
protected $secret;
EDIT: The issue happens because the form is submitted using a PATCH request.
In Symfony, the Form::submit
method is called by a Request Handler with this line:
$form->submit($data, 'PATCH' !== $method);
As a result the Form::submit
$clearMissing
parameter is set to false
in the case of a PATCH request, thus leaving the non-sent fields to their old value.
But I do not know how to solve the problem. If I explicitely pass a JSON {secret: false}
to the Symfony framework when the checkbox is not checked, it will interpret it as the "false"
string and consider that a true value, thus considering the checkbox checked...
NB. I have exactly the same issue with an array of checkboxes using a choice
field type (with multiple
and extended
to true
) linked to a Doctrine Simple Array property: as soon as a given checkbox has been sent once as checked, it is impossible to set back the related property to false
with subsequent unchecked
submissions.
回答1:
The issue happens because the form is submitted using a PATCH request.
This has lead to open this Symfony issue.
As explained, one workaround is to explicitely send a specific reserved value (for instance the string '__false') when the checkbox is unchecked (instead of sending nothing), and replace this value by 'null' using a custom data transformer in the form type:
// MyEntityFormType.php -- buildForm method
$builder->add('mycheckbox', ...);
$builder->get('mycheckbox')
->addViewTransformer(new CallbackTransformer(
function ($normalizedFormat) {
return $normalizedFormat;
},
function ($submittedFormat) {
return ( $submittedFormat === '__false' ) ? null : $submittedFormat;
}
));
The case with the 'choice' field can't be solved the same way. It is actually a bug of Symfony, dealt with in this issue.
回答2:
Non of above-mentioned didn't help me. So, I am using this...
Explanation
Resolution for this issue when "PATCH" method was used, was to add additional hidden "timestamp" field inside of a form type and to have it next to the checkbox of issue in twig file. This is needed to pass something along with the checkbox, that would definitely change - time-stamp will change.
Next thing was to use PRE_SUBMIT event and to wait for form field to arrive and if it not set, I would set it manually... Works fine, and I don't mind extra code...
FormType
$builder
...
->add('some_checkbox')
->add('time_stamp', 'hidden', ['mapped' => false, 'data' => time()])
...
Twig
{{ form_widget(form.time_stamp) }}
{{ form_widget(form.some_checkbox) }}
PRE_SUBMIT event in builder
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use($options) {
$data = $event->getData();
$form = $event->getForm();
if (!$data) {
return;
}
/* Note that PATCH method is added as an option for "createForm"
* method, inside of your controller
*/
if ($options["method"]=="PATCH" && !isset($data['some_checkbox'])) {
$form->getData()->setSomeCheckbox(false);//adding missing checkbox, since it didn't arrive through submit.. grrr
}
});
回答3:
What version of Symfony are you using?
There should exist some code dedicated to the situation you're writing about, in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php
, in Form::submit()
:
// Treat false as NULL to support binding false to checkboxes.
// Don't convert NULL to a string here in order to determine later
// whether an empty value has been submitted or whether no value has
// been submitted at all. This is important for processing checkboxes
// and radio buttons with empty values.
if (false === $submittedData) {
$submittedData = null;
} elseif (is_scalar($submittedData)) {
$submittedData = (string) $submittedData;
}
Located at lines 525-534 for me. Could you check this works properly for you?
Another lead would be a custom form subscriber that do not work exactly as intended - by overwriting the provided value.
回答4:
It's probably because the field isn't required on you schema. you can provide a default value to the checkbox with the following:
$builder->add('secret', 'checkbox', array(
'required' => false,
'empty_data' => false
));
See here or here
回答5:
This solution works for me.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('isActive', CheckboxType::class, array(
'required' => false
))
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $e {
$entity = $e->getData();
$form = $e->getForm();
$isActive = empty($_POST[$form->getName()]['isActive']) ? false : true;
$entity->setIsActive($isActive);
});
}
回答6:
Another possibility is to add a hidden element and make this with Javascript. It will fail in 0.1 % of the people that use a browser without javascript. This is a simple example for a multiple checkboxes FormType element:
->add('ranges', ChoiceType::class, array(
'label' => 'Range',
'multiple' => true,
'expanded' => true,
'choices' => array(
null => 'None',
'B1' => 'My range',
)
))
<script>
$(document).ready(function() {
function updateDynRanges(object) {
if (object.prop("checked")) {
document.getElementById('ranges_0').checked = 0;
} else {
document.getElementById('ranges_0').checked = 1;
}
}
// On page onload
$('#ranges_1').change(function() {
updateDynRanges($(this));
});
updateDynRanges($('ranges_1'));
}
</script>
If after testing works you can just add a visibility:false to the second checkbox.
Twig template:
{{ form_label(form.dynamicRanges) }}<br>
{{ form_widget(form.dynamicRanges[1]) }}
<div class="hidden">{{ form_widget(form.ranges[0]) }}</div>
Looks like an ugly workaround, but I just wanted to compete with the other ugly suggested workarounds, in this case mostly updating the twig template.
来源:https://stackoverflow.com/questions/35502979/symfony2-form-unchecked-checkbox-not-taken-into-account-why