Skip to content

HTML5 validation on required but triggerly hidden field. #1442

@Quendi6

Description

@Quendi6

Winter CMS Build

1.2.9

PHP Version

8.3

Database engine

MySQL/MariaDB

Plugins installed

No response

Issue description

Since version 1.2.9, HTML5 validation is enabled for all form fields. I don't know why, but this wasn't the case in previous versions (tested on versions 1.2.6 and 1.2.7; I can't verify for 1.2.8 but I think it was the same behavior).

Unfortunately, the browser now prevents form submission when a show/hide trigger makes a required field invisible, without displaying an error message, because the browser cannot focus on an invisible field.

Steps to replicate

Create a Model with

	use \Winter\Storm\Database\Traits\Validation;

	/**
	 * @var array Validation rules
	 */
	public $rules = [
		'bindings_qty' => 'required|integer|min:1',
	];

	public function beforeValidate()
	{
		if (!$this->bindings) unset($this->rules['bindings_qty'])
	}

and in his fields.yaml, put this:

fields:
    bindings:
      label: Bindings
      type: switch
    bindings_qty:
      label: Bindings quantity
      type: number
      trigger:
        action: show
        field: bindings
        condition: checked

When creating or updating a record from his form, make sure there is no value inside bindings_qty et then uncheck bindings.

Workaround

This JS file added to my FormController do the trick.

/*
 * Fix for WinterCMS 1.2.9+
 * Intercepts HTML5 validation to ignore fields hidden by triggers
 * and restores the behavior from before 1.2.9
 * 
 * This script restores the old behavior only for hidden fields.
 * They will not be validated by HTML5, even if they have the 'required' attribute.
 */
+function ($) { "use strict";

    /**
     * Checks if an element is visible (not hidden by display:none or the hide class)
     */
    function isElementVisible(element) {
        var $el = $(element);
        // Check if the element or one of its parents is hidden
        if ($el.hasClass('hide') || $el.is(':hidden')) {
            return false;
        }
        // Check parents
        var $parent = $el.closest('[data-trigger]');
        if ($parent.length && $parent.hasClass('hide')) {
            return false;
        }
        return true;
    }

    /**
     * Overrides checkValidity() to ignore hidden fields
     */
    if (typeof HTMLFormElement !== 'undefined' && HTMLFormElement.prototype.checkValidity) {
        var originalCheckValidity = HTMLFormElement.prototype.checkValidity;
        
        HTMLFormElement.prototype.checkValidity = function() {
            // Call the original validation
            var isValid = originalCheckValidity.call(this);
            
            // If the form is invalid, check if this is because of a hidden field
            if (!isValid) {
                var invalidFields = this.querySelectorAll(':invalid');
                var hasVisibleInvalid = false;
                
                for (var i = 0; i < invalidFields.length; i++) {
                    if (isElementVisible(invalidFields[i])) {
                        hasVisibleInvalid = true;
                        break;
                    }
                }
                
                // If all invalid fields are hidden, treat the form as valid
                if (!hasVisibleInvalid) {
                    return true;
                }
            }
            
            return isValid;
        };
    }

}(window.jQuery);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions