Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This form should not contain extra fields. #23

Open
leevigraham opened this issue Apr 19, 2024 · 5 comments
Open

This form should not contain extra fields. #23

leevigraham opened this issue Apr 19, 2024 · 5 comments

Comments

@leevigraham
Copy link

leevigraham commented Apr 19, 2024

When submitting a form with a dependent field if the dependent field is not shown then a "This form should not contain extra fields." error is shown.

$builder = new DynamicFormBuilder($builder);

$builder
    ->add('comparison', ChoiceType::class, [
        'choices' => [
            'is…' => 'eq',
            'is not…' => 'neq',
            'is empty' => 'empty',
        ]
    ])
    ->addDependent(
        name:'value',
        dependencies: ['comparison'],
        callback: function (DependentField $field, ?string $comparison) use ($options): void {
            if ($comparison === 'empty') {
                return;
            }
            $field->add(TextType::class, [
                'required' => false
            ]);
        }
    );

Video:

Screen.Recording.2024-04-19.at.20.50.53.mov

I'm not using any javascript to remove the value field before submission so the data is being submitted triggering the error.

I've also implemented this with PRE_SUBMIT on the parent form which checks the view data, adds / removes the value field and unsets the data which works without error.

// Add an PRE_SET_DATA event listener that adds or removes the value field based on the original comparison data
// This fires when the data is set on the form
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
    $form = $event->getForm();
    $data = $event->getData();

    $comparison = $data['comparison'] ?? null;

    if (!in_array($comparison, [ComparisonType::EMPTY, ComparisonType::NOT_EMPTY])) {
        $form->add('value', TextType::class, ['required' => false]);
    }
});

// Add a PRE_SUBMIT event listener that adds or removes the value field based on the submitted comparison data
// This fires when the form is submitted
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
    $form = $event->getForm();
    $data = $event->getData();

    $comparison = $data['comparison'] ?? null;

    if (!in_array($comparison, [ComparisonType::EMPTY, ComparisonType::NOT_EMPTY])) {
        $form->add('value', TextType::class, ['required' => false]);
        return;
    }

    // Remove the form field
    $form->remove('value');
    // Unset the value and the submitted data
    // Removing the submitted data removes the extra fields error
    unset($data['value']);
    $event->setData($data);

});
@bocharsky-bw
Copy link
Member

Yeah, if you don't use JS to drop the value field before form submit - then form events is the correct way to work around it. Thanks for sharing your solution with others!

If you have ideas on how to improve the package - please, feel free to open a PR

@leevigraham
Copy link
Author

leevigraham commented Apr 24, 2024

@bocharsky-bw experimenting with this some more and I think I found something that may be useful.

In my form I have added an additional "update" button that sets the following options:

  • 'validate' => false, - Adds a formnovalidate attribute which disables HTML5 validation if the form is submitted using this button
  • 'validation_groups' => false - Disables all validation on the form

image

If the 'update' button is clicked the form is submitted and all front end and back end validation is disabled.

Combine this with an updated on change listener which passes the update button through as the requester element:

image

and you have no errors on change:

Screen.Recording.2024-04-24.at.11.00.29.mov

Submitting the form with the submit button still triggers HTML5 and backend validation.

@bocharsky-bw
Copy link
Member

bocharsky-bw commented Apr 26, 2024

Hey @leevigraham ,

Oh wow, this is an interesting workaround! Thanks for such a detailed description with the nice demo!

Hm, having 2 buttons is a bummer, but seems that do the trick, and probably the additional button might be hidden with CSS. Though I wonder if the behavior may be different in different browsers :/

So this workaround solves your issue? Do you think we can improve our docs by mentioning this?

I'm still not sure we're not missing something simple here... Btw, I found another possible solution - Symfony Forms have allow_extra_fields feature, see https://symfony.com/doc/current/reference/forms/types/form.html#allow-extra-fields . So using it in your form like:

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'allow_extra_fields' => true,
    ]);
}

Should also do the trick probably because will allow the form to accept additional fields not defined in the form type. However, it might pose security risks if not handled properly.

@leevigraham
Copy link
Author

@bocharsky-bw allow_extra_fields definitely works… I'm looking for a solution that disables all validation and updates the form. During my experiments I've found that I can only disable validation for the current form and child forms (not bubble up validation to the root form). I'll keep exploring.

@janklan
Copy link

janklan commented Jun 25, 2024

I think allowing extra fields is risky. Adding $field->add(HiddenType::class, ['mapped' => false]); instead seems to do the trick: it will register the field in the form, and because it's not mapped, it won't get into the resulting form data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants