Validating multiple forms at once

74 views Asked by At

Our app has multiple identical forms on a page. Before submitting the data, I want to validate the inputs of all the forms with a single request from Vue.

I came up with the following frontend portion

await this.axios({
  method: 'POST',
  url: '/data/validate/MixtureFormRequest',
  data: this.forms, // array of forms with identical JSON structure.
});

MixtureFormRequest.php is just a request class which looks something like this:

class MixtureFormRequest extends FormRequest
{
    public function rules()
    {
        return [
            'key1'         => ['required'],
            'key2'         => ['required'],
        ];
    }
}

Now the tricky part is in the controller:

Route::post('validate/{validationClass}', function (string $validationClass, Request $request) {

    $errors = [];

    foreach($request as $form) {
        $validator = app("App\\Http\\Requests\\" . $validationClass);
        $validationInstance = $validator->make($form, $validator->rules());

        if ($validationInstance->fails()) {
            $errors[] = $validationInstance->errors();
        }
    }

    return response()->jsonSuccess(['errors' => $errors]);
});

I have the above, but $errors only has a single element. It validates the first form, fails and then sends me errors for that form. I would like errors for each form at once.

Is that possible?

1

There are 1 answers

1
Riza Khan On

I couldn't get this to work by sending all the forms at once. Instead I created multiple requests like so:

        async $validateForms(controller, forms) {
            const formsToValidate = forms.map((form) => {
                return this.$axios({
                    method: 'POST',
                    url: `/data/validate/${controller}`,
                    data: form,
                });
            });

            const results = await Promise.allSettled(formsToValidate);

            return results.map(({ reason, status }) => {
                if (status === 'rejected') {
                    return reason.data.errors;
                } else {
                    return {};
                }
            });
        },

On the backend, it becomes quite simple:

    Route::post('validate/{validationClass}', function (string $validationClass, Request $request) {
        app("App\\Http\\Requests\\" . $validationClass);
        return response()->jsonSuccess([]);
    });

This allows the frontend to control which validation class to use for that particular request.