laravel-admin icon indicating copy to clipboard operation
laravel-admin copied to clipboard

hasMany form validation not working on single submit click

Open Sivan4562 opened this issue 1 year ago • 4 comments

  • Laravel Version: ^10.10
  • PHP Version: 8.1
  • Laravel-admin: ^1.8

Description:

Hi Team, I am using the hasMany form and I use the ->rules('required') for the form required field when I click the submit button the first time the validation error does not throw the error message when I click the second time it shows the error. Do you know how I can fix this? I attached my code as below.

This is form data

$form->hasMany('customer_experience','Experience Info',function (Form\NestedForm $form) {
   $form->text('title', 'Title')->rules('required');
   $form->text('company', 'Company')->rules('required');
   $form->text('location', 'Location')->rules('required');
   $form->date('start_date', 'Start Date')->rules('required');
   $form->date('end_date', 'End Date')->rules('required');
});

And model

public function customer_experience(){
       return $this->hasMany(CustomerExperience::class, 'customer_id');
}

Can anyone help me to fix this bug?

Sivan4562 avatar Sep 13 '23 10:09 Sivan4562

  1. Can you check DevTools to see if after first Submit click the request is being sent?
  2. Does it happen for a specific field or for any?
  3. Does it happen for a new hasMany entry or only when updating existing?
  4. Does the form has Tabs or other non-typical field that can "steal" focus?

alexoleynik0 avatar Sep 13 '23 14:09 alexoleynik0

Hi @alexoleynik0, Good morning

  1. Yes when I submit the form the network shows the response call. I will be attached the screenshot below.
  2. The validation does not work only for hasMany at the first time.
  3. The hasMany does not throw an error when a new form is submitted and edits the existing form.

This is the form structure I have created: image

During the First submission form it does not show an error image

After clicking the submit button a second time it shows the error image

Here the dev tool network response image

Sivan4562 avatar Sep 14 '23 05:09 Sivan4562

Ok, now I see the issue on my side too.. Strangely, but I'm not sure we can fix it easily. It seems that it's tied / similar to #2097 and #4612 issues.

In the PR #4976 it almost fixed by @shacky , so you can create your custom HasMany field based on this PR like so:

<?php

namespace App\Admin\Extensions\Form;

use Encore\Admin\Form\Field\HasMany;
use Encore\Admin\Form\NestedForm;
use Exception;
use Illuminate\Database\Eloquent\Relations\HasMany as Relation;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Arr;

class HasManyCustom extends HasMany
{
    /**
     * Build Nested form for related data.
     *
     * @return array
     *
     * @throws Exception
     */
    protected function buildRelatedForms()
    {
        if (is_null($this->form)) {
            return [];
        }

        $model = $this->form->model();

        $relation = call_user_func([$model, $this->relationName]);

        if (! $relation instanceof Relation && ! $relation instanceof MorphMany) {
            throw new Exception('hasMany field must be a HasMany or MorphMany relation.');
        }

        $forms = [];

        /*
         * If redirect from `exception` or `validation error` page.
         *
         * Then get form data from session flash.
         *
         * Else get data from database.
         */
        if ($values = old($this->column)) {
            foreach ($values as $key => $data) {
                if (1 == $data[NestedForm::REMOVE_FLAG_NAME]) {
                    continue;
                }

                $model = $relation->getRelated()->replicate()->forceFill($data);

                $forms[$key] = $this->buildNestedForm($this->column, function ($form) use ($key) {
                    $form->setKey($key);
                    call_user_func($this->builder, $form);
                }, $model)
                    ->fill($data)
                ;
            }
        } else {
            if (empty($this->value)) {
                return [];
            }

            foreach ($this->value as $data) {
                $key = Arr::get($data, $relation->getRelated()->getKeyName());

                $model = $relation->getRelated()->replicate()->forceFill($data);

                $forms[$key] = $this->buildNestedForm($this->column, $this->builder, $model)
                    ->fill($data)
                ;
            }
        }

        return $forms;
    }
}

Then declare it's use in app/Admin/bootstrap.php like so:

\Encore\Admin\Form::extend('hasManyCustom', \App\Admin\Extensions\Form\HasManyCustom::class);

And use it instead of default hasMany in your Forms:

$form->hasManyCustom('orders', __('Orders'), function (Form\NestedForm $nestedForm) {
    $nestedForm->text('active', 'active')->rules('required');
});

alexoleynik0 avatar Sep 14 '23 13:09 alexoleynik0

Unfortunately, that does not fix the issue with wrong new_{index} that happens after the form has been submitted and you try to add new items to HasMany field - it creates them starting with new_1 key and so on, that could be already used, so unpredictable bugs can occur -- you will get only one new Item where you expect to get two+ etc.

But that is a separate issue to yours.

alexoleynik0 avatar Sep 14 '23 13:09 alexoleynik0