diff --git a/packages/alpinejs/src/directives/x-model.js b/packages/alpinejs/src/directives/x-model.js
index eab094d85..1b17ba797 100644
--- a/packages/alpinejs/src/directives/x-model.js
+++ b/packages/alpinejs/src/directives/x-model.js
@@ -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)) {
setValue(
getInputValue(el, modifiers, { target: el }, getValue())
);
@@ -91,7 +92,7 @@ directive('model', (el, { modifiers, expression }, { effect, cleanup }) => {
// on nextTick so the page doesn't end up out of sync
if (el.form) {
let removeResetListener = on(el.form, 'reset', [], (e) => {
- nextTick(() => el._x_model && el._x_model.set(el.value))
+ nextTick(() => el._x_model && el._x_model.set(getInputValue(el, modifiers, { target: el }, getValue())))
})
cleanup(() => removeResetListener())
}
@@ -149,7 +150,7 @@ function getInputValue(el, modifiers, event, currentValue) {
newValue = event.target.value
}
- return event.target.checked ? currentValue.concat([newValue]) : currentValue.filter(el => ! checkedAttrLooseCompare(el, newValue))
+ return event.target.checked ? (currentValue.includes(newValue) ? currentValue : currentValue.concat([newValue])) : currentValue.filter(el => !checkedAttrLooseCompare(el, newValue));
} else {
return event.target.checked
}
diff --git a/tests/cypress/integration/directives/x-model.spec.js b/tests/cypress/integration/directives/x-model.spec.js
index ca01dc83f..7bd6e9f57 100644
--- a/tests/cypress/integration/directives/x-model.spec.js
+++ b/tests/cypress/integration/directives/x-model.spec.js
@@ -210,6 +210,169 @@ test('x-model updates value when the form is reset',
}
)
+test(
+ "x-model radio updates value when the form is reset",
+ html`
+
+
+
+
+ `,
+ ({ get }) => {
+ get("span").should(haveText("radio2"));
+ get("input[value='radio1']").click();
+ get("span").should(haveText("radio1"));
+ get("button").click();
+ get("span").should(haveText("radio2"));
+ }
+);
+
+test(
+ "x-model.number radio updates value when the form is reset",
+ html`
+
+
+
+ `,
+ ({ get }) => {
+ get("[x-data]").should(haveData("foo", 2));
+ get("input[value='1']").click();
+ get("[x-data]").should(haveData("foo", 1));
+ get("button").click();
+ get("[x-data]").should(haveData("foo", 2));
+ }
+);
+
+test(
+ "x-model.boolean radio updates value when the form is reset",
+ html`
+
+
+
+ `,
+ ({ get }) => {
+ get("[x-data]").should(haveData("foo", true));
+ get("input[value='false']").click();
+ get("[x-data]").should(haveData("foo", false));
+ get("button").click();
+ get("[x-data]").should(haveData("foo", true));
+ }
+);
+
+test(
+ "x-model checkbox array updates value when the form is reset",
+ html`
+
+
+
+
+ `,
+ ({ get }) => {
+ get("span").should(haveText("checkbox2,checkbox3"));
+ get("input[value='checkbox1']").click();
+ get("span").should(haveText("checkbox2,checkbox3,checkbox1"));
+ get("input[value='checkbox3']").click();
+ get("span").should(haveText("checkbox2,checkbox1"));
+ get("button").click();
+ get("span").should(haveText("checkbox2,checkbox3"));
+ }
+);
+
+test(
+ "x-model.number checkbox array updates value when the form is reset",
+ html`
+
+
+
+ `,
+ ({ get }) => {
+ get("[x-data]").should(haveData("foo", [2, 3]));
+ get("input[value='1']").click();
+ get("[x-data]").should(haveData("foo", [2, 3, 1]));
+ get("input[value='3']").click();
+ get("[x-data]").should(haveData("foo", [2, 1]));
+ get("button").click();
+ get("[x-data]").should(haveData("foo", [2, 3]));
+ }
+);
+
+test(
+ "x-model select updates value when the form is reset",
+ html`
+
+
+
+ `,
+ ({ get }) => {
+ get("[x-data]").should(haveData("a", "456"));
+ get("[x-data]").should(haveData("b", ["123", "789"]));
+ get("[x-data]").should(haveData("c", 456));
+ get("[x-data]").should(haveData("d", [123, 789]));
+ get("select#a").select("789");
+ get("select#b").select("456");
+ get("select#c").select("789");
+ get("select#d").select("456");
+ get("[x-data]").should(haveData("a", "789"));
+ get("[x-data]").should(haveData("b", ["456"]));
+ get("[x-data]").should(haveData("c", 789));
+ get("[x-data]").should(haveData("d", [456]));
+ get("button").click();
+ get("[x-data]").should(haveData("a", "456"));
+ get("[x-data]").should(haveData("b", ["123", "789"]));
+ get("[x-data]").should(haveData("c", 456));
+ get("[x-data]").should(haveData("d", [123, 789]));
+ }
+);
+
+
test('x-model with fill modifier takes input value on null, empty string or undefined',
html`
@@ -236,7 +399,7 @@ test('x-model with fill modifier takes input value on null, empty string or unde
test('x-model with fill modifier works with select elements',
html`
-
+
123
456
@@ -245,11 +408,31 @@ test('x-model with fill modifier works with select elements',
123
456
+
+ 123
+ 456
+
+
+ 123
+ 456
+
+
+ true
+ false
+
+
+ true
+ false
+
`,
({ get }) => {
get('[x-data]').should(haveData('a', '456'));
get('[x-data]').should(haveData('b', ['123', '456']));
+ get('[x-data]').should(haveData('c', 456));
+ get('[x-data]').should(haveData('d', [123, 456]));
+ get('[x-data]').should(haveData('e', true));
+ get('[x-data]').should(haveData('f', [true, false]));
}
);