From ef92d105e0965dd82d8b630831f4d24a76f2b99c Mon Sep 17 00:00:00 2001 From: Varixo Date: Thu, 26 Dec 2024 10:56:57 +0100 Subject: [PATCH] fix: textarea with null value --- .changeset/red-trains-deny.md | 5 +++++ packages/qwik/src/core/client/vnode-diff.ts | 10 ++++----- packages/qwik/src/core/shared/error/error.ts | 2 +- .../src/core/shared/utils/jsx-filename.ts | 2 +- packages/qwik/src/core/ssr/ssr-render-jsx.ts | 4 ++-- .../qwik/src/core/tests/component.spec.tsx | 22 ++++++++++++++++++- packages/qwik/src/server/ssr-container.ts | 6 ++--- 7 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 .changeset/red-trains-deny.md diff --git a/.changeset/red-trains-deny.md b/.changeset/red-trains-deny.md new file mode 100644 index 00000000000..41418c4a044 --- /dev/null +++ b/.changeset/red-trains-deny.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/core': patch +--- + +fix: textarea with null value diff --git a/packages/qwik/src/core/client/vnode-diff.ts b/packages/qwik/src/core/client/vnode-diff.ts index 52047efee2a..2a8e67a129a 100644 --- a/packages/qwik/src/core/client/vnode-diff.ts +++ b/packages/qwik/src/core/client/vnode-diff.ts @@ -104,7 +104,7 @@ import { } from '../signal/signal-subscriber'; import { serializeAttribute } from '../shared/utils/styles'; import { QError, qError } from '../shared/error/error'; -import { getFileNameFromJsx } from '../shared/utils/jsx-filename'; +import { getFileLocationFromJsx } from '../shared/utils/jsx-filename'; export type ComponentQueue = Array; @@ -660,13 +660,13 @@ export const vnode_diff = ( } if (elementName === 'textarea' && key === 'value') { - if (typeof value !== 'string') { + if (value && typeof value !== 'string') { if (isDev) { - throw qError(QError.wrongTextareaValue, [currentFile]); + throw qError(QError.wrongTextareaValue, [currentFile, value]); } continue; } - (element as HTMLTextAreaElement).value = escapeHTML(value); + (element as HTMLTextAreaElement).value = escapeHTML((value as string) || ''); continue; } @@ -712,7 +712,7 @@ export const vnode_diff = ( vCurrent && vnode_isElementVNode(vCurrent) && elementName === vnode_getElementName(vCurrent); const jsxKey: string | null = jsx.key; let needsQDispatchEventPatch = false; - const currentFile = getFileNameFromJsx(jsx.dev); + const currentFile = getFileLocationFromJsx(jsx.dev); if (!isSameElementName || jsxKey !== getKey(vCurrent)) { // So we have a key and it does not match the current node. // We need to do a forward search to find it. diff --git a/packages/qwik/src/core/shared/error/error.ts b/packages/qwik/src/core/shared/error/error.ts index 55f0adc7ce4..6816a81efbd 100644 --- a/packages/qwik/src/core/shared/error/error.ts +++ b/packages/qwik/src/core/shared/error/error.ts @@ -45,7 +45,7 @@ export const codeToText = (code: number, ...parts: any[]): string => { 'Serialization Error: Serialization of data type {{0}} is not implemented', // 37 'Serialization Error: Unvisited {{0}}', // 38 'Serialization Error: Missing QRL chunk for {{0}}', // 39 - '{{0}}\nThe value of the textarea must be a string', // 40 + '{{0}}\nThe value of the textarea must be a string found {{1}}', // 40 'Unable to find q:container', // 41 "Element must have 'q:container' attribute.", // 42 'Unknown vnode type {{0}}.', // 43 diff --git a/packages/qwik/src/core/shared/utils/jsx-filename.ts b/packages/qwik/src/core/shared/utils/jsx-filename.ts index 688e31f2870..6f4e8a7763b 100644 --- a/packages/qwik/src/core/shared/utils/jsx-filename.ts +++ b/packages/qwik/src/core/shared/utils/jsx-filename.ts @@ -1,6 +1,6 @@ import type { DevJSX } from '../jsx/types/jsx-node'; -export function getFileNameFromJsx(jsxDev?: DevJSX): string | null { +export function getFileLocationFromJsx(jsxDev?: DevJSX): string | null { if (!jsxDev) { return null; } diff --git a/packages/qwik/src/core/ssr/ssr-render-jsx.ts b/packages/qwik/src/core/ssr/ssr-render-jsx.ts index 12236fc5995..354d9f0afcb 100644 --- a/packages/qwik/src/core/ssr/ssr-render-jsx.ts +++ b/packages/qwik/src/core/ssr/ssr-render-jsx.ts @@ -35,7 +35,7 @@ import type { ISsrComponentFrame, ISsrNode, SSRContainer, SsrAttrs } from './ssr import { qInspector } from '../shared/utils/qdev'; import { serializeAttribute } from '../shared/utils/styles'; import { QError, qError } from '../shared/error/error'; -import { getFileNameFromJsx } from '../shared/utils/jsx-filename'; +import { getFileLocationFromJsx } from '../shared/utils/jsx-filename'; class ParentComponentData { constructor( @@ -183,7 +183,7 @@ function processJSXNode( appendClassIfScopedStyleExists(jsx, options.styleScoped); let qwikInspectorAttrValue: string | null = null; if (isDev && jsx.dev && jsx.type !== 'head') { - qwikInspectorAttrValue = getFileNameFromJsx(jsx.dev); + qwikInspectorAttrValue = getFileLocationFromJsx(jsx.dev); if (qInspector) { appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue); } diff --git a/packages/qwik/src/core/tests/component.spec.tsx b/packages/qwik/src/core/tests/component.spec.tsx index 2273f36df79..5e210c93c4b 100644 --- a/packages/qwik/src/core/tests/component.spec.tsx +++ b/packages/qwik/src/core/tests/component.spec.tsx @@ -17,6 +17,7 @@ import { useTask$, useVisibleTask$, type JSXOutput, + type PropsOf, type Signal as SignalType, } from '@qwik.dev/core'; import { domRender, ssrRenderToDom, trigger } from '@qwik.dev/core/testing'; @@ -480,6 +481,25 @@ describe.each([ await expect(document.querySelector('textarea')).toMatchDOM(); }); + it('should render textarea without error', async () => { + const Textarea = component$>( + ({ ['bind:value']: valueSig, value, ...props }) => { + return ( + <> + ); + }); + it('should not render textarea value for non-text value', async () => { const qErrorSpy = vi.spyOn(qError, 'qError'); const Cmp = component$(() => { @@ -502,7 +522,7 @@ describe.each([ ); } catch (e) { expect((e as Error).message).toBeDefined(); - expect(qErrorSpy).toHaveBeenCalledWith(QError.wrongTextareaValue); + expect(qErrorSpy).toHaveBeenCalledWith(QError.wrongTextareaValue, expect.anything()); } }); diff --git a/packages/qwik/src/server/ssr-container.ts b/packages/qwik/src/server/ssr-container.ts index 1afb11bb8bf..89b8af915ca 100644 --- a/packages/qwik/src/server/ssr-container.ts +++ b/packages/qwik/src/server/ssr-container.ts @@ -1176,13 +1176,13 @@ class SSRContainer extends _SharedContainer implements ISSRContainer { } if (tag === 'textarea' && key === 'value') { - if (typeof value !== 'string') { + if (value && typeof value !== 'string') { if (isDev) { - throw qError(QError.wrongTextareaValue, [currentFile]); + throw qError(QError.wrongTextareaValue, [currentFile, value]); } continue; } - innerHTML = escapeHTML(value); + innerHTML = escapeHTML(value || ''); key = QContainerAttr; value = QContainerValue.TEXT; }