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

Fix form reset for x-model radio, checkbox arrays, select multiple and various modifiers #4159

Merged
merged 1 commit into from
Apr 22, 2024

Conversation

bb
Copy link
Contributor

@bb bb commented Apr 19, 2024

This PR fixes form reset for many input types (radio, checkbox array, select multiple) plain as well as in combination with number and boolean modifiers for casting as well as fill modifier for <select multiple and also fixes duplicated entries with checkbox arrays during reset.

A few tests have been added, all of them were failing before this PR and are good now.

Some of the fixes in more detail:

  • Fix form reset for x-model radio inputs.
    • Without this fix, always the value of the last radio input (in the test: radio3) is set to the model.
  • Fix form reset for x-model checkbox array inputs.
    • Without this fix, always the value of the last checkbox input (in this test: checkbox4) is set to the model (no matter if it was checked or not).
  • Fix form reset for x-model radio inputs with number and boolean modifiers
    • Without this reset would set strings to the model
  • Fix form reset for select multiple
  • Fix fill for select multiple
  • Fix x-model select multiple with number and boolean modifiers
    • Without this reset would set strings to the model

... and possibly a few more.

@bb bb marked this pull request as draft April 19, 2024 13:45
@bb bb marked this pull request as ready for review April 19, 2024 14:33
@bb bb changed the title Fix form reset for x-model radio inputs Fix form reset for x-model radio inputs and checkbox array inputs Apr 19, 2024
Fix form reset for x-model radio inputs
Fix form reset for x-model checkbox array inputs
Fix form reset for x-model radio inputs with number and boolean modifiers
Fix x-model select multiple with number and boolean modifiers
Fix form reset for select multiple
@bb
Copy link
Contributor Author

bb commented Apr 21, 2024

I started out adding more and more conditions in the reset listener but settled on simply always using the getInputValue approach because I basically ended up duplicating all the conditions from there anyway. In between it looked like this:

nextTick(() => el._x_model && (el.type !== 'radio' || el.checked) && (((el.type === 'checkbox' && Array.isArray(getValue())) || el.type === 'radio' || (el.tagName.toLowerCase() === 'select')) ? setValue(getInputValue(el, modifiers, { target: el }, getValue())) : el._x_model.set(el.value)))

now it's just

nextTick(() => el._x_model && el._x_model.set(getInputValue(el, modifiers, { target: el }, getValue())))

I kept using the public setter (which was prepared to allow programmatic overriding of x-model as described in a comment below that line). However, there are some places in the code which do not use the overridable setter: cloning and when using .fill. So I wonder if there are more bugs hidden in this area. I recommend adding a test for overriding the setter to make sure there are none.

@bb bb changed the title Fix form reset for x-model radio inputs and checkbox array inputs Fix form reset for x-model radio, checkbox arrays, select multiple and various modifiers Apr 21, 2024
Copy link
Contributor

@ekwoka ekwoka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of improvements for some simple changes.

@@ -71,7 +71,8 @@ directive('model', (el, { modifiers, expression }, { effect, cleanup }) => {

if (modifiers.includes('fill'))
if ([undefined, null, ''].includes(getValue())
|| (el.type === 'checkbox' && Array.isArray(getValue()))) {
|| (el.type === 'checkbox' && Array.isArray(getValue()))
|| (el.tagName.toLowerCase() === 'select' && el.multiple)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
|| (el.tagName.toLowerCase() === 'select' && el.multiple)) {
|| (el.tagName === 'SELECT' && el.multiple)) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is definitely fine for HTML4 and HTML5, I'm afraid it would break usage in XHTML documents. Not sure about SVG, never used Alpine in an SVG context (yet).

Also, there are two other places checking for this tagName using toLowerCase comparison. If it is changed, it should be changed in all places.

Copy link
Contributor Author

@bb bb Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made me curious, so I verified. It does not seem to break XHTML documents, at least not in current Firefox, Chrome, nor Safari versions (on Desktop). It gets weird when embedding svg inline in XHTML, though.... but honestly, who has not switched to HTML5 within the last 15 or so years 😃

So I'm quite sure either approach is fine here.

I don't have any old stuff or IE available for testing currently... not relevant for me, not sure about Alpine's promises in this direction.

Example (validated using https://validator.w3.org/check) prints every element uppercased:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>x</title>
</head><body>
<div>
<select name="s">
<option>foo</option>
</select>
</div>
<script type="text/javascript">
    document.querySelectorAll("*").forEach(e => console.log(e.tagName))
</script>
</body></html>

prints every element uppercased.

Interestingly, when embedding SVG without explicit namespaces, tag names for svg are lowercase. When embedding SVG with explicit namespace, they're uppercase.

Tagnames svg and path are lowercase, while HTML elements stay uppercase, e.g. SELECT, svg

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>x</title>
</head><body>
<div>
<select name="s">
<option>foo</option>
</select>
<svg viewBox="0 0 10 10" style="background-color:#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" x="0px" y="0px" width="10" height="10">
    <path d="M 3 3 L 3 7 L 7 7 L 7 3 L 3 3 Z" fill="#f00"/>
</svg>
</div>
<script type="text/javascript">
    document.querySelectorAll("*").forEach(e => console.log(e.tagName))
</script>
</body></html>

Tagnames uppercase with namespace prefix (e.g. SVG:SVG):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xml:lang="en" lang="en">
<head>
<title>x</title>
</head><body>
<div>
<select name="s">
<option>foo</option>
</select>
<svg:svg viewBox="0 0 10 10" style="background-color:#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" x="0px" y="0px" width="10" height="10">
    <svg:path d="M 3 3 L 3 7 L 7 7 L 7 3 L 3 3 Z" fill="#f00"/>
</svg:svg>
</div>
<script type="text/javascript">
    document.querySelectorAll("*").forEach(e => console.log(e.tagName))
</script>
</body></html>

@calebporzio
Copy link
Collaborator

Thanks @bb! Thanks for all your work on this

@calebporzio calebporzio merged commit 6e670fe into alpinejs:main Apr 22, 2024
1 check passed
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

Successfully merging this pull request may close these issues.

3 participants