inertiajs / inertia-laravel

The Laravel adapter for Inertia.js.
https://inertiajs.com
MIT License
2.01k stars 224 forks source link

Validate multi step form - with Interia or Axios? #553

Closed torbentschechne closed 9 months ago

torbentschechne commented 9 months ago

Hello,

this is not a specific issue with Inertia, more a question of how to tackle my problem. I hope this is okay to ask the question here, as it's being specific for Inertia/Laravel and I get no answers on Stackoverflow.

I use InertiaJS and Laravel for a web application and I have created a Multi Step Form. For the Form I have used the Inertia helper useForm. Now, when clicking the button to go to the next step, I want to send a validation request of the form to a validation controller. I ask myself how I can achieve this.

First, I thought I can do something like this:

form
    .transform((data) => ({
        ...data,
        step : activeStepIndex.value,
    }))
    .post(route('setup.validate'), {
    preserveState: true,
    preserveScroll: true,
});

This seems to send a request, but the endpoint is sending a 302 response and according to the docs, as far as I understand it, it needs to do a redirect - https://inertiajs.com/redirects / https://inertiajs.com/forms#submitting-forms Usually I thought that even when I return an Inertia redirect/view that Inertia only re-renders the errors? I checked the console and I can see that it calls the validate endpoint, and gets a redirect to setup. But within setup, I have no errors in the props. What does the controller needs to do, to have the errors being populated?

Then I thought, that I can use a classic axios call. Here I have the issue, that I submit the whole form to the validation form request, and therefore I need a validation rule like this:

return match ($this->input('step')) {
    '0' => [
        'form.company' => ['required', 'string', 'max:255'],
    ],
};

The issue now is, that the response has a key named form.company, but the response must be just company, as I access the error like this, through the Inertia form: form.errors.company.

So somehow, within my axios call, I need to map the errors from the response with the form errors of the Inertia object:

catch((error) => {
    form.errors = error.response.data.errors;
});

But as I said, this does not work, because the key is not nested into:

"form" : {
    "company": 

It is just: form.company as being the whole key.

Now I ask myself whats the correct solution here? Is there another Inertia method that I should use or is axios the right thing to use here? Should I use form.setError within my catch block, loop through the errors and set the keys and error messages specifically?

When using axios, can I somehow return just company as the key and not form.company?

Does anybody can help?

torbentschechne commented 9 months ago

Honestly, this is a bit embarissing. So it works with using

form
    .transform((data) => ({
        ...data,
        step : activeStepIndex.value,
    }))
    .post(route('setup.validate'), {
    preserveState: true,
    preserveScroll: true,
});

but "step" is not a string, but an int. That's why my match did not work. Interesting though, because axios did send the variable as a string to the backend. So it seems that using the Inertia form helper and issuing a post request can be used for backend validation!