sl-input validation not respected in htmx form submission!
Closed this issue · 2 comments
tapegram commented
Hello! I just started using this extension, which is great, and was hoping that it could be expanded to help with this case:
<form hx-post="/s/htmxservicestarter/todos" hx-target="#todos" hx-swap="afterbegin swap:1s" data-form-type="other" class="">
<div class="hflex">
<sl-input name="description" type="text" required="" placeholder="Enter a new todo" size="medium" form="" data-required="" data-invalid="" data-user-invalid=""></sl-input>
<sl-button type="submit" variant="default" size="medium" data-optional="" data-valid="" data-user-valid="">New</sl-button>
</div>
</form>
The input is required, but htmx still fires off the post when clicked:
Screen.Recording.2024-05-05.at.11.53.00.AM.mov
Is this something that could be easily added here? (I'm happy to do it but don't know enough about the htmx implementation yet to get started). Or is this possibly just user error?
Either way, thanks for the help and thanks for this extension!
tapegram commented
Ok immediately after posting this I found something that worked for me (though I'm not sure it is the best solution)
I just added a check on elt.checkValidity
and preventDefault if false. It appears to work in the above case.
const slTypes = 'sl-checkbox, sl-color-picker, sl-input, sl-radio-group, sl-range, sl-rating, sl-select, sl-switch, sl-textarea'
/* Lightly modified version of the same function in htmx.js */
function shouldInclude(elt) {
// sl-rating doesn't have a name attribute exposed through the Shoelace API (for elt.name) so this check needs to come before the name==="" check
if (elt.tagName === 'SL-RATING' && elt.getAttribute('name')) {
return true
}
if (elt.name === "" || elt.name == null || elt.disabled || elt.closest("fieldset[disabled]")) {
return false
}
if (elt.tagName === 'SL-CHECKBOX' || elt.tagName === 'SL-SWITCH') {
return elt.checked
}
if (elt.tagName === "SL-RADIO-GROUP") {
return elt.value.length > 0
}
return true;
}
htmx.defineExtension('shoelace', {
onEvent: function(name, evt) {
if ((name === "htmx:configRequest") && (evt.detail.elt.tagName === 'FORM')) {
evt.detail.elt.querySelectorAll(slTypes).forEach((elt) => {
if (shouldInclude(elt)) {
if (!elt.checkValidity()) {
evt.preventDefault();
return;
}
if (elt.tagName === 'SL-CHECKBOX' || elt.tagName === 'SL-SWITCH') {
// Shoelace normally does this bit internally when the formdata event fires, but htmx doesn't fire the formdata event, so we do it here instead. See https://github.com/shoelace-style/shoelace/issues/1891
evt.detail.parameters[elt.name] = elt.value || 'on'
} else if (elt.tagName == 'SL-RATING') {
evt.detail.parameters[elt.getAttribute('name')] = elt.value
} else {
evt.detail.parameters[elt.name] = elt.value
}
}
})
}
}
})
benopotamus commented
Fixed in latest version