Prechádzať zdrojové kódy

Fix initial value setting for boolean radio

Caleb Porzio 1 rok pred
rodič
commit
2a566bb464

+ 6 - 13
index.html

@@ -10,18 +10,11 @@
     <!-- <script src="//cdn.tailwindcss.com"></script> -->
     <!-- <script src="//cdn.tailwindcss.com"></script> -->
 
-    <hr> <hr> <hr> <hr> <hr>
-    <div x-data>
-        <button id="target">Button</button>
-
-        <article
-            x-anchor.bottom
-            x-anchor:to="document.getElementById('target')"
-            :style="{ left: $anchor.x+'px', top: $anchor.y+'px' }"
-            style="position: absolute; left: 0;"
-        >
-            Tooltip contents
-        </article>
+    <div x-data="{ val: true }"
+    >
+   <input type="text" x-model.boolean="val">
+   <input type="checkbox" x-model.boolean="val">
+   <input type="radio" name="foo" value="true" x-model.boolean="val">
+   <input type="radio" name="foo" value="false" x-model.boolean="val">
     </div>
-    <hr> <hr> <hr> <hr> <hr>
 </html>

+ 1 - 13
packages/alpinejs/src/directives/x-model.js

@@ -2,7 +2,7 @@ import { evaluateLater } from '../evaluator'
 import { directive } from '../directives'
 import { mutateDom } from '../mutation'
 import { nextTick } from '../nextTick'
-import bind from '../utils/bind'
+import bind, { safeParseBoolean } from '../utils/bind'
 import on from '../utils/on'
 import { warn } from '../utils/warn'
 import { isCloning } from '../clone'
@@ -186,18 +186,6 @@ function safeParseNumber(rawValue) {
     return isNumeric(number) ? number : rawValue
 }
 
-function safeParseBoolean(rawValue) {
-    if ([1, '1', 'true', true].includes(rawValue)) {
-        return true
-    }
-
-    if ([0, '0', 'false', false].includes(rawValue)) {
-        return false
-    }
-
-    return rawValue ? Boolean(rawValue) : null
-}
-
 function checkedAttrLooseCompare(valueA, valueB) {
     return valueA == valueB
 }

+ 17 - 1
packages/alpinejs/src/utils/bind.js

@@ -49,7 +49,11 @@ function bindInputValue(el, value) {
 
         // @todo: yuck
         if (window.fromModel) {
-            el.checked = checkedAttrLooseCompare(el.value, value)
+            if (typeof value === 'boolean') {
+                el.checked = safeParseBoolean(el.value) === value
+            } else {
+                el.checked = checkedAttrLooseCompare(el.value, value)
+            }
         }
     } else if (el.type === 'checkbox') {
         // If we are explicitly binding a string to the :value, set the string,
@@ -130,6 +134,18 @@ function checkedAttrLooseCompare(valueA, valueB) {
     return valueA == valueB
 }
 
+export function safeParseBoolean(rawValue) {
+    if ([1, '1', 'true', true].includes(rawValue)) {
+        return true
+    }
+
+    if ([0, '0', 'false', false].includes(rawValue)) {
+        return false
+    }
+
+    return rawValue ? Boolean(rawValue) : null
+}
+
 function isBooleanAttr(attrName) {
     // As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute
     // Array roughly ordered by estimated usage

+ 19 - 1
tests/cypress/integration/directives/x-model.spec.js

@@ -1,4 +1,4 @@
-import { haveData, haveText, haveValue, html, test } from '../../utils'
+import { beChecked, haveData, haveText, haveValue, html, notBeChecked, test } from '../../utils'
 
 test('The name of the test',
     html`<h1 x-data x-text="'HEY'"></h1>`,
@@ -79,6 +79,24 @@ test('x-model with number modifier returns: null if empty, original value if cas
     }
 )
 
+test('x-model casts value to boolean initially for radios',
+    html`
+    <div x-data="{ foo: true }">
+        <input id="1" type="radio" value="true" name="foo" x-model.boolean="foo">
+        <input id="2" type="radio" value="false" name="foo" x-model.boolean="foo">
+    </div>
+    `,
+    ({ get }) => {
+        get('div').should(haveData('foo', true))
+        get('#1').should(beChecked())
+        get('#2').should(notBeChecked())
+        get('#2').click()
+        get('div').should(haveData('foo', false))
+        get('#1').should(notBeChecked())
+        get('#2').should(beChecked())
+    }
+)
+
 test('x-model casts value to boolean if boolean modifier is present',
     html`
     <div x-data="{ foo: null, bar: null, baz: [] }">