Skip to content

data-model value norender|* throws Uncaught Error: Invalid model name "*" when csrf token is being generated #2769

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

Open
FluffyDiscord opened this issue May 23, 2025 · 2 comments
Labels
Bug Bug Fix Status: Needs Review Needs to be reviewed

Comments

@FluffyDiscord
Copy link

I have component that first renders with "data-model"="norender|*". If there are errors after first submit, I change the data-model to on(input)|* to basically allow "validation in real time".

Both should be valid data models, as the first one is even listed in Symfony docs.

Immediately after clicking the send button for the first time, the included csrf_protection_controller.js that came with Symfony 7.2 installation throws the following error:

Uncaught Error: Invalid model name "*".
    at Component.set (@symfony_ux-live-component_dist_live_controller__js.js?v=2893b870:1698:13)
    at extended.updateModelFromElementEvent (@symfony_ux-live-component_dist_live_controller__js.js?v=2893b870:2799:20)
    at extended.handleChangeEvent (@symfony_ux-live-component_dist_live_controller__js.js?v=2893b870:2756:10)
    at HTMLDivElement.callback (@symfony_ux-live-component_dist_live_controller__js.js?v=2893b870:2570:52)
    at generateCsrfToken (csrf_protection_controller.js:36:19)
    at HTMLDocument.<anonymous> (csrf_protection_controller.js:6:5)

The form works, the CSRF controller does set the cookie (or at least it's visible in requests headers the component makes), so everything seems to be working.

I noticed this by chance in production, as I was checking out my new fancy form.

Symfony 7.2
symfony/stimulus-bundle: 2.25.2
symfony/ux-live-component: 2.25.2
symfony/ux-turbo: 2.25.2
symfony/ux-twig-component: 2.25.2

@FluffyDiscord FluffyDiscord added the Bug Bug Fix label May 23, 2025
@carsonbot carsonbot added the Status: Needs Review Needs to be reviewed label May 23, 2025
@smnandre
Copy link
Member

Could you share with us the template and the (related) part of the LiveComponent class ?

@FluffyDiscord
Copy link
Author

FluffyDiscord commented May 24, 2025

The component looks like this

<div {{ attributes }}>
    {{ form(form, {
        attr: {
            'data-live-action-param': 'sendForm',
            'class': 'mb-1',
        }
    }) }}
</div>

It's using basically the default Symfony div form theme, sprinkled with additional TailwindCSS, so nothing there.

Live component

<?php

namespace App\Twig\Components;

use App\Form\Type\ContactType;
use App\Form\UX\LazilyValidatedComponentWithFormTrait;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent]
class ContactForm extends AbstractController
{
    use DefaultActionTrait;
    use LazilyValidatedComponentWithFormTrait;

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(ContactType::class);
    }

    #[LiveAction]
    public function sendForm(): void
    {
        $this->submitForm();

        $contact = $this->form->getData();
        // ...
    }
}

ContactType is simple Symfony form, few fields usnig built-in Symfony types.

The lazy trait

<?php

namespace App\Form\UX;

use Symfony\UX\LiveComponent\ComponentWithFormTrait;

trait LazilyValidatedComponentWithFormTrait
{
    use ComponentWithFormTrait;

    private function getDataModelValue(): ?string
    {
        return null;
    }

    // this function is being used by the original form trait!
    private function useNameAttributesAsModelName(): void
    {
        $modelValue = $this->getDataModelValue();
        $attributes = $this->getFormView()->vars['attr'] ?: [];

        // enable lazy form validation
        // will enable on-input validation using LiveFormValidationExtension
        // once an error has been detected on submitting
        if ($modelValue !== null) {
            $attributes["data-model"] = $modelValue;
        }

        $this->getFormView()->vars['attr'] = $attributes;
    }
}

Form extension changing the data-model attribute

<?php

namespace App\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;

// enables live validation when a form has errors
// after first submit
class LiveFormValidationExtension extends AbstractTypeExtension
{
    public function buildView(FormView $view, FormInterface $form, array $options): void
    {
        if ($form->getParent() !== null) {
            return;
        }

        $view->vars['attr']['novalidate'] = true;
        $view->vars['attr']['data-action'] = 'live#action:prevent';
        $view->vars['attr']['data-model'] = 'norender|*';

        $withErrors = $form->isSubmitted() && !$form->isValid();
        if ($withErrors) {
            $view->vars['attr']['data-model'] = 'on(input)|*';
        }
    }

    public static function getExtendedTypes(): iterable
    {
        return [FormType::class];
    }

I believe this should be everything that's related to this component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Bug Fix Status: Needs Review Needs to be reviewed
Projects
None yet
Development

No branches or pull requests

3 participants