I have a form containing a checkbox and a "value field". The value field could be anything, a text box, a compound field, a collection - anything.
The form could look like this, for example:
field_1_label enabled [x]
value [________]
field_2_label enabled [x]
value sub_field_1 [________]
sub_field_2 [________]
field_3_label enabled [x]
value [________]
When the "enabled" field contains true, everything works fine already. When the "enabled" field contains false, I would like to disable validation on the value field and it's child fields.
So when "enabled" is un-checked, I will effectively ignore the field. I will still display it in the form, but I won't store the data and I certainly don't want it validated.
Does anybody have suggestions for how I might do this? Specifically, I'm having problems getting the validation system to ignore the value field and any potential child fields.
In Symfony 2.3 you can use false in validation_groups to have no constraints applied:
https://symfony.com/doc/current/form/button_based_validation.html
So for example, on the field containing the checkbox and value field:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver
->setDefaults([
'validation_groups' => function(FormInterface $form) {
// If the form is disabled, don't use any constraints
if ($form->get('enabled_checkbox')->getData() == false) {
return false;
}
// Otherwise, use the default validation group
return 'Default';
}
]);
}
Just remove the child fields prior to validation if the parent's checkbox is set to false.
Read more in the cookbook article How to Dynamically Modify Forms Using Form Events.
Subscribe to form events FormEvents::POST_SET_DATA and remove the field in your subscriber.
The section Adding an Event Subscriber to a Fom class covers this topic.
You can aswell introduce different validation groups for your form.
Just apply another validation group ( not containing the chield fields ) if the parent's checkbox is set to false.
Related
I would like to know if there is any way to put null value by default in the easyadmin_autocomplete select.
The first item in the list is selected and filled with data from database but i need a null value by default and setted automaticly. The goal is a first result point to an empty one (Choose one...).
Do you know how to do it?
Can you think of any way combining the options defined below?
#easy_admin.yml
Product:
class: App\Entity\Product
controller: App\Controller\ProductController
new:
fields:
- { property: 'category', label: 'Category', type: 'easyadmin_autocomplete', type_options: { class: 'App\Entity\Category' } }
}
In this example, one select has a placeholder with the text 'Any' (Ninguno). I need to know why is handling them different.
These are the options defined for the attr fields -> type_options of the yml:
action
allow_extra_fields
allow_file_upload
attr
auto_initialize
block_name
by_reference
class
compound
constraints
csrf_field_name
csrf_message
csrf_protection
csrf_token_id
csrf_token_manager
data
data_class
disabled
empty_data
error_bubbling
error_mapping
extra_fields_message
help
help_attr
inherit_data
invalid_message
invalid_message_parameters
label
label_attr
label_format
mapped
method
multiple
post_max_size_message
property_path
required
translation_domain
trim
upload_max_size_message
validation_groups
If setting your default value would be a solution for you (like zero), service listener might be an answer:
// You need to add this listener yourself:
class ProductServiceListener
{
...
// you can manipulate entity in this level as you wish:
public function preUpdate(LifeCycleEventArgs $args)
{
// You will focus to Product entity, so block others:
if (!(get_class($entity) == 'App\Entity\Product')) {
return;
}
// Set whatever default value you want if it's null:
if($entity->getCategory() == null) {
$entity->setCategory(0); // Zero, as an example.
}
There is no way to set a placeholder like value for easyadmin_autocomplete.
The normal way for a choice type is to use the placeholder option as described in the symfony documentation. But easyadmin_autocomplete does not extend that type and it is a standalone type. Can't you use a choice type or entity type with the placeholder option. The only need for the easyadmin_autocomplete type is if there are a lot of entities and it will slow the application if all are loaded on the page.
My best bet is that you can extend the easyadmin_autocomplete. Because the easyadmin_autocomplete uses EntityType you can add the option for placeholder in the configureOptions method in the extended type. That will delegate the option to the EntityType but even then it is not displayed in the html because of the select2 javascript which also needs to be modified.
If it is a must I recommend the way to extend the type, add the option and also add custom javascript to easyadmin that will handle the new type and add the placeholder option. You can see the select2 documentation on how to set the placeholder.
But if you can use the entity or choice type for your select it is the preferred solution.
I need to modify a field in the SUBMIT form event, but when I do any validation rules on the field are lost.
This is all that's happening in the form type (the title field isn't actually being changed I'm just using it as an example):
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add("title");
$builder->addEventListener(FormEvents::SUBMIT, function(FormEvent $event) {
$form = $event->getForm();
$form->add("title");
});
}
Any validation rules for 'title' are now lost, either annotation rules defined with the entity or using a separate validator class.
Can I do anything to keep the validation or is it intended that validation rules don't get run for fields which are modified in the SUBMIT event?
If you can handle the FormEvents::POST_SUBMIT event instead of FormEvents::SUBMIT you will keep the validation. You will need to make sure that the listener is on the child form that you want to edit, otherwise you will have an issue with not being able to add a field to a submitted form.
In this instance you're not actually modifying a field you're adding a new one with $form->add('title') which will replace the existing 'title' field within the form (which is why the validation constraints are disappearing). You might want to look into validation groups for the type of functionality you're aiming for unless you want to elaborate on what you're doing within the submit event?
I can not find the opportunity to customize the attributes on radio buttons separately, because I want to insert a title tag and data-toggle="tooltip" to display a tooltip on every radio buttons
$builder
->add('type', 'choice', array(
'choices' => array(
'0' => 'Demande', // Here personnalise attr
'1' => 'Recherche', // Here personnalise attr
),
'expanded' => true,
))
I tried with the attr option, but it puts on all the radio buttons ... Or should that EVERY radio button is a different attr.
Thank you !
The expanded choice list in Symfony is actually a form with children of either type radio or type checkbox (depending on the multiple option being false or true respectively).
In my opinion, the best way to solve this, is create a custom type, and do your own templating of the type. This usually is the most clear to the fellow developer and is consistent (and much easier than you might think).
The type should look like this:
class MyType extends AbstractType()
{
public function getName()
{
return 'tooltip_choice';
}
public function getParent()
{
return 'choice';
}
}
Add this class to your service definitions and tag it as a form type (see docs on this).
Now, the form templating layer will search for a block named tooltip_choice_row (for the row of the element), tooltip_choice_widget for the widget of the element. If you inspect the default form templates, you can easily dissect how the choice list rendering works in the default implementation. You can either copy and paste it to your custom form theming and override.
The downside of this solution is that it costs a little bit more code, but you can much easier extend your types to include the tooltip itself, and pass that as an option to your form type as well.
Another solution would be to override the radio_widget and the checkbox_widget blocks in your form template, and check if the parent is a choice block. You can find out what exact variables you need by dumping the _context variable in your template, it shows exactly what values are available for you to check on.
I have an embedded form (for Address) which has its own validations for various properties. I embed this form in a parent form (for Person), and I have a checkbox on the parent form that says something like "Person has an address?"
When the checkbox is left unchecked, I want to disable all the validation for the embedded Address form. Or, better yet, if I can just remove the embedded form from being submitted completely that would be OK too.
I looked at using validation groups, but the use case doesn't match my own.
OK, figured this out. When adding the AddressType embedded form in my form builder, I just pass in the option for validation groups like so:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$form->add('address', new AddressType(), array(
'label' => 'Address',
'validation_groups' => function (FormInterface $form) {
if ($form->getParent()->get('toggleAddress')->getData() === false) {
return array();
}
return array('Default');
}
));
});
Within the validation group function, a check is made to see if the toggle to enable Address is off. If so, return a blank array, with removes all validation groups, including the "Default" one.
You try to fix your issue with validation group which will not cover your use case (it can but it will be tricky because en empty Address object will be linked to your Person object).
Basically, you embed your Address form everytime whereas it should only be embed when the checkbox is checked. IMHO, you should rely on dynamic form as explained here.
With this solution, you will need extra JS code in order to update you form when you click the checkbox in order to update the whole form accordingly. Then, there will be no issue about validation because the Address object will only be created when the form is embed.
Additionally (just for information), you can add/edit validation groups according to the submitted data as explained here.
Hope my answer is helpfull!
Can I set a general form error with callback validator? I do not want to set it to a specific field, but rather to a form in general errors.
Yes, you have to create what we call a class constraint, which will be applied to the data_class itself, not to a specific field: http://symfony.com/doc/2.0/book/validation.html#classes
Here is a snippet of code to set an error to your global form and not on a field.
public function isValid(ExecutionContext $context) {
if (what ever condition) {
// Do not set the property path as shown in the documentation
$context->addViolation('This name sounds totally fake!', array(), null);
}
}
When you do not define a property path on the context, the violation is added on top level of the form. all you have to do is remove these two lines given in the official documentation :
$propertyPath = $context->getPropertyPath() . '.firstName';
$context->setPropertyPath($propertyPath);
And afterwards simple display the global errors of your form.
{{ form_errors(form) }}