Skip to content
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

Re-Validate form on input change or manually re-validate #1004

Open
kennethenglisch opened this issue Mar 12, 2024 · 0 comments
Open

Re-Validate form on input change or manually re-validate #1004

kennethenglisch opened this issue Mar 12, 2024 · 0 comments

Comments

@kennethenglisch
Copy link

Subject of the issue

I have a form with date range picker and two time pickers. The time pickers validation is based on the input of the other time picker and the range picker.

If the date range is only one day, the start time should be before the end time. Also I can only validate the time pickers when the user entered a date range first.

Is it possible to re-trigger the whole form validation on form-submit or re-validate the whole form after any input has changed?

The problem is that if I enter the times and try to submit the time pickers say I need to pick a date first. Which is correct. If I now enter the date range and submit again, the time pickers are still tagged as invalid and are not revalidated at this point.

Your environment

  • version of this package: 4.8.1
  • version of Laravel: 10.44.0

Steps to reproduce

TimeRule

class TimeRule implements ValidationRule
{
    private string|null $date_range;
    private string|null $time_start;
    private string|null $time_end;

    private string $date_range_label;
    private string $time_start_label;
    private string $time_end_label;

    public function __construct(string|null $date_range, string|null $time_start, string|null $time_end, string $date_range_label, string $time_start_label, string $time_end_label)
    {
        $this->date_range   = $date_range;
        $this->time_start   = $time_start;
        $this->time_end     = $time_end;

        $this->date_range_label = $date_range_label;
        $this->time_start_label = $time_start_label;
        $this->time_end_label   = $time_end_label;
    }

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if($this->date_range === null) {
            $fail(t('vacation::create-edit.choose-range-first', ['attr' => $this->date_range_label]));
            return;
        }

        if($this->time_start === null) {
            $fail(t('vacation::create-edit.choose-time-start-first', ['attr' => $this->time_start_label]));
            return;
        }

        if($this->time_end === null) {
            $fail(t('vacation::create-edit.choose-time-end-first', ['attr' => $this->time_end_label]));
            return;
        }

        $dates = explode(' ', $this->date_range);
        if(sizeof($dates) === 3) {
            return;
        }

        $isStartTime = $value === $this->time_start;
        $now = date(config('app.params.timeFormat'));
        $today = date(config('app.params.dateFormat'));
        try {
            $date = strtotime($dates[0]);

            if(!$date) {
                $fail(t('dateRangeRules.error'));
                return;
            }

            $date = date(config('app.params.dateFormat'), $date);
            $start_date = strtotime($dates[0] . ' ' . $this->time_start);
            $end_date = strtotime($dates[0] . ' ' . $this->time_end);

            if(!$start_date || !$end_date) {
                $fail(t('vacation::create-edit.time-invalid'));
                return;
            }

            $start_date = date(config('app.params.dateTimeFormat'), $start_date);
            $end_date = date(config('app.params.dateTimeFormat'), $end_date);

            if($date === $today) {
                $today_now = strtotime($today . ' ' . $now);

                if(!$today_now) {
                    $fail(t('dateRangeRules.error'));
                    return;
                }

                $today_now = date(config('app.params.dateTimeFormat'), $today_now);
                if($today_now > $start_date && $isStartTime || $today_now > $end_date && !$isStartTime) {
                    $fail(t('vacation::create-edit.time-before-now'));
                    return;
                }
            }

            if($start_date >= $end_date) {
                $fail(t('vacation::create-edit.end-time-before-start-time', ['start' => $this->time_start_label, 'end' => $this->time_end_label]));
                return;
            }
        } catch (Exception $e) {
            $fail(t('dateRangeRules.error'));
            return;
        }
    }
}

Rules in Request Class

/**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
     */
    public function rules(): array
    {
        $vacation_types = VacationTypes::forUserRoles(auth()->user()->getUserRolesIds())->toArray();
        $vacation_types_list = '';

        foreach($vacation_types as $vacation_type) {
            $vacation_types_list .= $vacation_type['id'] . ',';
        }

        return [
            'vacation-type' => ['required', 'integer', 'in:' . rtrim($vacation_types_list, ',')],
            'date-range'    => ['required', new DateRangeRule()],
            'full-day'      => ['integer', 'in:1,null', 'nullable'],
            'time-start'    => ['required_unless:full-day,1', 'min:5', 'max:5', 'regex:/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/', 'nullable', new TimeRule($this->input('date-range'), $this->input('time-start'), $this->input('time-end'), t('vacation::create-edit.date-range-label'), t('vacation::create-edit.time-start-label'), t('vacation::create-edit.time-end-label'))],
            'time-end'      => ['required_unless:full-day,1', 'min:5', 'max:5', 'regex:/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/', 'nullable', new TimeRule($this->input('date-range'), $this->input('time-start'), $this->input('time-end'), t('vacation::create-edit.date-range-label'), t('vacation::create-edit.time-start-label'), t('vacation::create-edit.time-end-label'))],
        ];
    }

Expected behaviour

The form should be revalidated when the user submits the form.
Better would be to have an option to revalidate everything after one input has changed

Actual behaviour

The input fields tagged as invalid should be valid after the user entered the date range but the fields are still tagges as invalid stating that the user should enter the date range first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant