feat: trigger form refresh for dob when completely entered only
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
import { Controller } from '@hotwired/stimulus'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors birthday input fields (day, month, year) and dispatches a custom event
|
||||||
|
* only when all three fields are filled with valid values.
|
||||||
|
*
|
||||||
|
* This prevents premature HTMX refreshes when users are still entering the date,
|
||||||
|
* improving UX by waiting until the complete date is entered.
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ['day', 'month', 'year']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all birthday fields are filled and dispatches a completion event.
|
||||||
|
*
|
||||||
|
* Called on input/change events from the day, month, and year fields.
|
||||||
|
* Only dispatches the 'birthday:complete' event when all three fields
|
||||||
|
* contain valid values that could form a complete date.
|
||||||
|
*/
|
||||||
|
check() {
|
||||||
|
const day = this.dayTarget.value.trim()
|
||||||
|
const month = this.monthTarget.value.trim()
|
||||||
|
const year = this.yearTarget.value.trim()
|
||||||
|
|
||||||
|
if (false === this.isComplete(day, month, year)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.dispatchEvent(new CustomEvent('birthday:complete', { bubbles: true }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that all date components are filled with plausible values.
|
||||||
|
*
|
||||||
|
* @param {string} day The day value
|
||||||
|
* @param {string} month The month value
|
||||||
|
* @param {string} year The year value
|
||||||
|
*
|
||||||
|
* @returns {boolean} True if all fields contain complete values
|
||||||
|
*/
|
||||||
|
isComplete(day, month, year) {
|
||||||
|
// Day: 1-2 digits
|
||||||
|
if (0 === day.length || day.length > 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month: 1-2 digits
|
||||||
|
if (0 === month.length || month.length > 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Year: exactly 4 digits for a complete year
|
||||||
|
if (4 !== year.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -253,8 +253,24 @@
|
|||||||
'year': 'Jahr'
|
'year': 'Jahr'
|
||||||
} -%}
|
} -%}
|
||||||
{%- set field_order = ['day', 'month', 'year'] -%}
|
{%- set field_order = ['day', 'month', 'year'] -%}
|
||||||
|
|
||||||
|
{# Check if HTMX attributes are present - if so, use birthday controller for deferred triggering #}
|
||||||
|
{%- set has_htmx = attr['hx-trigger'] is defined -%}
|
||||||
|
{%- set htmx_attrs = {} -%}
|
||||||
|
{%- if has_htmx -%}
|
||||||
|
{# Extract HTMX attributes and replace trigger with custom event #}
|
||||||
|
{%- set htmx_attrs = {
|
||||||
|
'hx-trigger': 'birthday:complete',
|
||||||
|
'hx-post': attr['hx-post']|default(''),
|
||||||
|
'hx-target': attr['hx-target']|default('#main-content'),
|
||||||
|
'hx-swap': attr['hx-swap']|default('innerHTML')
|
||||||
|
} -%}
|
||||||
|
{# Remove HTMX attrs from main attr to avoid duplication #}
|
||||||
|
{%- set attr = attr|filter((v, k) => k not in ['hx-trigger', 'hx-post', 'hx-target', 'hx-swap']) -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' flex items-center space-x-2')|trim}) -%}
|
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' flex items-center space-x-2')|trim}) -%}
|
||||||
<div {{ block('widget_container_attributes') }}>
|
<div {{ block('widget_container_attributes') }}{% if has_htmx %} {{ stimulus_controller('birthday') }}{% for key, value in htmx_attrs %} {{ key }}="{{ value }}"{% endfor %}{% endif %}>
|
||||||
{%- for field_name in field_order -%}
|
{%- for field_name in field_order -%}
|
||||||
{%- set child = form[field_name] -%}
|
{%- set child = form[field_name] -%}
|
||||||
{%- set child_attr = child.vars.attr|default({}) -%}
|
{%- set child_attr = child.vars.attr|default({}) -%}
|
||||||
@@ -262,6 +278,12 @@
|
|||||||
'placeholder': placeholders[field_name],
|
'placeholder': placeholders[field_name],
|
||||||
'class': (child_attr.class|default('') ~ ' form-field')|trim
|
'class': (child_attr.class|default('') ~ ' form-field')|trim
|
||||||
}) -%}
|
}) -%}
|
||||||
|
{%- if has_htmx -%}
|
||||||
|
{%- set child_attr = child_attr|merge({
|
||||||
|
'data-birthday-target': field_name,
|
||||||
|
'data-action': 'change->birthday#check'
|
||||||
|
}) -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
{{- form_widget(child, {'attr': child_attr}) -}}
|
{{- form_widget(child, {'attr': child_attr}) -}}
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
|
|||||||
Reference in New Issue
Block a user