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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions