symfony / ux

Symfony UX initiative: a JavaScript ecosystem for Symfony
https://ux.symfony.com/
MIT License
820 stars 297 forks source link

[LiveComponent] instantiateForm with previous default values #676

Closed rwkt closed 1 year ago

rwkt commented 1 year ago

$post will be null on first load which is fine, but after submitting the form (with incomplete form), $post is still null.

Is it possible to return the submitted $post entity and use it in instantiateForm?

    #[Route('/new', name: 'post_new', methods: ['GET', 'POST'])]
    public function new(Request $request): Response
    {
        return $this->render('post/new.html.twig');
    }
use ComponentWithFormTrait;
use DefaultActionTrait;

#[LiveProp(fieldName: 'data')]
public ?Post $post = null;

protected function instantiateForm(): FormInterface
{
    $post = $this->post;
    // this is always null even after form is submitted
    if (is_null($post)) {
        $post = new Post();
        $post->setTitle(‘example’);
    }

    return $this->createForm(PostType::class, $post);
}

#[LiveAction]
public function save()
{
    $this->submitForm();

    $form = $this->getFormInstance();

    /** @var Post $post */
    $post = $form->getData();
    $this->postRepository->add($post, true);

    return $this->redirectToRoute(‘post_show’, [
        'id' => $post->getId(),
    ]);
}
weaverryan commented 1 year ago

Hi there!

Hmm. What exactly do you want to accomplish? You're right that, after submitting an incomplete form, $this->post will still be null. But, assuming your PostType has a data_class set to Post::class, your form will already have created a Post object behind the scenes, which is now "bound" to the form. So Post is still null, but there IS a Post object attached to your form. That's why, to give you the best answer, I'd like to know what you want to accomplish :).

Is it, perhaps, that you are using the $post property in your template to render some stuff? And you'd like that data to be rendered after submitting an incomplete form? If so, doing this should be easier in the next version of Live Components - after #670 is merged. One that is merged, you'll be able to ALWAYS set the Post property, even if it's non-persisted (currently, setting a LiveProp to a non-persisted entity causes a hydration error). Basically, you'll be able to always set the property, like:

protected function instantiateForm(): FormInterface
{
    if (null === $this->post) {
        $this->post = new Post();
    }

    return $this->createForm(PostType::class, $this->post);
}

Anyways, that'll be possible after #670. But right now, you can actually ALSO get this to work, you'll just need a, sort of, fake hydration system for this property. Try this: do the above code for instantiateForm(). Then add this:

#[LiveProp(fieldName: 'data', hydrateWith: 'hydratePost', dehydrateWith: 'dehydratePost')]
public ?Post $post = null;

public function dehydratePost(Post $post)
{
    return null;
}

public function hydratePost($data)
{
    return new Post();
}

Let me know if that helps :).