diff --git a/.changeset/neat-maps-tickle.md b/.changeset/neat-maps-tickle.md new file mode 100644 index 00000000000..d915f03fc86 --- /dev/null +++ b/.changeset/neat-maps-tickle.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/core': patch +--- + +fix: input's value is string when passing number diff --git a/packages/docs/src/routes/docs/(qwik)/components/rendering/index.mdx b/packages/docs/src/routes/docs/(qwik)/components/rendering/index.mdx index 517f13ecf0a..b76a5c7186e 100644 --- a/packages/docs/src/routes/docs/(qwik)/components/rendering/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/components/rendering/index.mdx @@ -180,11 +180,17 @@ The `bind:` is compiled away by the Qwik optimizer to a property set and an even import { component$, useSignal } from '@qwik.dev/core'; export default component$(() => { + const count = useSignal(0); const firstName = useSignal(''); const acceptConditions = useSignal(false); return (
+ {/* For number inputs, use `valueAsNumber` instead of `value` to get the numeric value directly */} + count.value = el.valueAsNumber } + /> firstName.value = el.value } diff --git a/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts b/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts index a21dd50bb50..ba0b9ec8231 100644 --- a/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts +++ b/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts @@ -596,7 +596,7 @@ type SpecialAttrs = { * For type: HTMLInputTypeAttribute, excluding 'button' | 'reset' | 'submit' | 'checkbox' | * 'radio' */ - 'bind:value'?: Signal; + 'bind:value'?: Signal; enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' | undefined; height?: Size | undefined; max?: number | string | undefined; diff --git a/packages/qwik/src/core/tests/use-signal.spec.tsx b/packages/qwik/src/core/tests/use-signal.spec.tsx index c2c8de9a911..88eee505058 100644 --- a/packages/qwik/src/core/tests/use-signal.spec.tsx +++ b/packages/qwik/src/core/tests/use-signal.spec.tsx @@ -651,5 +651,44 @@ describe.each([ ); }); + + // help me to get a description + it('should update the sum when input values change', async () => { + const AppTest = component$(() => { + const a = useSignal(1); + const b = useSignal(2); + return ( +
+ {a.value} + {b.value} = {a.value + b.value} + + +
+ ); + }); + + const { document } = await render(, { debug: debug }); + + await expect(document.querySelector('div')).toMatchDOM( +
+ 1 + 2 = 3 + + +
+ ); + + const input1 = document.querySelector('#input1')! as HTMLInputElement; + + input1.value = '10'; + input1.valueAsNumber = 10; + + await trigger(document.body, input1, 'input'); + await expect(document.querySelector('div')).toMatchDOM( +
+ 10 + 2 = 12 + + +
+ ); + }); }); }); diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_input_bind.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_input_bind.snap index 484f8902902..b33df57257f 100644 --- a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_input_bind.snap +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_input_bind.snap @@ -42,7 +42,7 @@ export const Greeter = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl(()=>{ "value": value, "onInput$": /*#__PURE__*/ inlinedQrl((_, elm)=>{ const [value] = useLexicalScope(); - return value.value = elm.value; + return value.value = elm.type == "number" ? elm.valueAsNumber : elm.value; }, "s_6IZeYpXCNXA", [ value ]) @@ -51,7 +51,7 @@ export const Greeter = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl(()=>{ "checked": checked, "onInput$": /*#__PURE__*/ inlinedQrl((_, elm)=>{ const [checked] = useLexicalScope(); - return checked.value = elm.checked; + return checked.value = elm.type == "number" ? elm.valueAsNumber : elm.checked; }, "s_JPI3bLCVnso", [ checked ]) @@ -60,7 +60,7 @@ export const Greeter = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl(()=>{ "stuff": stuff, "onChange$": /*#__PURE__*/ inlinedQrl((_, elm)=>{ const [stuff] = useLexicalScope(); - return stuff.value = elm.stuff; + return stuff.value = elm.type == "number" ? elm.valueAsNumber : elm.stuff; }, "s_eyREJ0lZTFw", [ stuff ]) diff --git a/packages/qwik/src/optimizer/core/src/transform.rs b/packages/qwik/src/optimizer/core/src/transform.rs index d692a781db7..ad19ce8b9b7 100644 --- a/packages/qwik/src/optimizer/core/src/transform.rs +++ b/packages/qwik/src/optimizer/core/src/transform.rs @@ -1311,17 +1311,59 @@ impl<'a> QwikTransform<'a> { ), ), op: ast::AssignOp::Assign, - right: Box::new(ast::Expr::Member( - ast::MemberExpr { - obj: Box::new(ast::Expr::Ident(elm)), - prop: ast::MemberProp::Ident( - ast::IdentName::new( - prop_name, DUMMY_SP, - ), - ), + right: Box::new(ast::Expr::Cond(ast::CondExpr { + test: Box::new(ast::Expr::Bin(ast::BinExpr { + left: Box::new(ast::Expr::Member( + ast::MemberExpr { + obj: Box::new(ast::Expr::Ident( + elm.clone(), + )), + prop: ast::MemberProp::Ident( + ast::IdentName::new( + "type".into(), + DUMMY_SP, + ), + ), + span: DUMMY_SP, + }, + )), span: DUMMY_SP, - }, - )), + op: ast::BinaryOp::EqEq, + right: Box::new(ast::Expr::Lit( + ast::Lit::Str(ast::Str { + value: "number".into(), + span: DUMMY_SP, + raw: None, + }), + )), + })), + cons: Box::new(ast::Expr::Member( + ast::MemberExpr { + obj: Box::new(ast::Expr::Ident( + elm.clone(), + )), + prop: ast::MemberProp::Ident( + ast::IdentName::new( + "valueAsNumber".into(), + DUMMY_SP, + ), + ), + span: DUMMY_SP, + }, + )), + alt: Box::new(ast::Expr::Member( + ast::MemberExpr { + obj: Box::new(ast::Expr::Ident(elm)), + prop: ast::MemberProp::Ident( + ast::IdentName::new( + prop_name, DUMMY_SP, + ), + ), + span: DUMMY_SP, + }, + )), + span: DUMMY_SP, + })), span: DUMMY_SP, }), ))),