Skip to content

Commit dce9976

Browse files
committed
fix: setting undefined as input value
1 parent 1fb75e7 commit dce9976

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

.changeset/tough-plants-stay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
fix: setting undefined as input value

packages/qwik/src/core/client/vnode-diff.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ export const vnode_diff = (
857857
const setAttribute = (key: string, value: any, vHost: ElementVNode) => {
858858
vHost.setAttr(
859859
key,
860-
value !== null ? serializeAttribute(key, value, scopedStyleIdPrefix) : null,
860+
value != null ? serializeAttribute(key, value, scopedStyleIdPrefix) : null,
861861
journal
862862
);
863863
};

packages/qwik/src/core/client/vnode.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -946,19 +946,18 @@ export const vnode_applyJournal = (journal: VNodeJournal) => {
946946
key = 'class';
947947
}
948948
const value = journal[idx++] as string | null | boolean;
949+
const shouldRemove = value == null || value === false;
949950
if (isBooleanAttr(element, key)) {
950951
(element as any)[key] = parseBoolean(value);
951-
} else if (key === 'value' && key in element) {
952-
(element as any).value = String(value);
953952
} else if (key === dangerouslySetInnerHTML) {
954953
(element as any).innerHTML = value!;
955954
element.setAttribute(QContainerAttr, QContainerValue.HTML);
955+
} else if (shouldRemove) {
956+
element.removeAttribute(key);
957+
} else if (key === 'value' && key in element) {
958+
(element as any).value = String(value);
956959
} else {
957-
if (value == null || value === false) {
958-
element.removeAttribute(key);
959-
} else {
960-
element.setAttribute(key, String(value));
961-
}
960+
element.setAttribute(key, String(value));
962961
}
963962
break;
964963
case VNodeJournalOpCode.HoistStyles:

packages/qwik/src/core/tests/component.spec.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,61 @@ describe.each([
27562756
expect(propsProxy[_PROPS_HANDLER]?.$effects$?.size).toBe(0);
27572757
});
27582758

2759+
it('should correctly set undefined value', async () => {
2760+
const Cmp = component$(() => {
2761+
const someValue = useSignal<string | undefined>(undefined);
2762+
return (
2763+
<div>
2764+
<input value={someValue.value} />
2765+
2766+
<button
2767+
id="foo"
2768+
onClick$={() => {
2769+
someValue.value = 'foo';
2770+
}}
2771+
></button>
2772+
<button
2773+
id="undefined"
2774+
onClick$={() => {
2775+
someValue.value = undefined;
2776+
}}
2777+
></button>
2778+
</div>
2779+
);
2780+
});
2781+
2782+
const { vNode, document } = await render(<Cmp />, { debug });
2783+
expect(vNode).toMatchVDOM(
2784+
<Component>
2785+
<div>
2786+
<input value={undefined} />
2787+
<button id="foo"></button>
2788+
<button id="undefined"></button>
2789+
</div>
2790+
</Component>
2791+
);
2792+
await trigger(document.body, 'button#foo', 'click');
2793+
expect(vNode).toMatchVDOM(
2794+
<Component>
2795+
<div>
2796+
<input value="foo" />
2797+
<button id="foo"></button>
2798+
<button id="undefined"></button>
2799+
</div>
2800+
</Component>
2801+
);
2802+
await trigger(document.body, 'button#undefined', 'click');
2803+
expect(vNode).toMatchVDOM(
2804+
<Component>
2805+
<div>
2806+
<input value={undefined} />
2807+
<button id="foo"></button>
2808+
<button id="undefined"></button>
2809+
</div>
2810+
</Component>
2811+
);
2812+
});
2813+
27592814
describe('regression', () => {
27602815
it('#3643', async () => {
27612816
const Issue3643 = component$(() => {

0 commit comments

Comments
 (0)