Skip to content

Commit

Permalink
fix(compiler-ssr): fix ssr compile error for select with non-option c…
Browse files Browse the repository at this point in the history
…hildren (vuejs#9442)

fix vuejs#9440
  • Loading branch information
edison1105 authored and lumozx committed Oct 21, 2023
1 parent 49aaa8f commit fcf7e50
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 26 deletions.
51 changes: 51 additions & 0 deletions packages/compiler-ssr/__tests__/ssrVModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,57 @@ describe('ssr: v-model', () => {
}></option></select></div>\`)
}"
`)

expect(
compileWithWrapper(`<select multiple v-model="model"><slot/></select>`)
.code
).toMatchInlineSnapshot(`
"const { ssrRenderSlot: _ssrRenderSlot, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple>\`)
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
_push(\`</select></div>\`)
}"
`)

expect(
compileWithWrapper(`
<select multiple v-model="model">
<optgroup label="foo">
<option value="bar">bar</option>
</optgroup>
</select>`).code
).toMatchInlineSnapshot(`
"const { ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${
_ssrRenderAttrs(_attrs)
}><select multiple><optgroup label=\\"foo\\"><option value=\\"bar\\"\${
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
? _ssrLooseContain(_ctx.model, \\"bar\\")
: _ssrLooseEqual(_ctx.model, \\"bar\\"))) ? \\" selected\\" : \\"\\"
}>bar</option></optgroup></select></div>\`)
}"
`)

expect(
compileWithWrapper(`
<select multiple v-model="model">
<optgroup label="foo">
<slot/>
</optgroup>
</select>`).code
).toMatchInlineSnapshot(`
"const { ssrRenderSlot: _ssrRenderSlot, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup label=\\"foo\\">\`)
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
_push(\`</optgroup></select></div>\`)
}"
`)
})

test('<input type="radio">', () => {
Expand Down
61 changes: 35 additions & 26 deletions packages/compiler-ssr/src/transforms/ssrVModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,38 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
}
}

function processOption(plainNode: PlainElementNode) {
if (plainNode.tag === 'option') {
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
const value = findValueBinding(plainNode)
plainNode.ssrCodegenNode!.elements.push(
createConditionalExpression(
createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [
createConditionalExpression(
createCallExpression(`Array.isArray`, [model]),
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
model,
value
]),
createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
model,
value
])
)
]),
createSimpleExpression(' selected', true),
createSimpleExpression('', true),
false /* no newline */
)
)
}
} else if (plainNode.tag === 'optgroup') {
plainNode.children.forEach(option =>
processOption(option as PlainElementNode)
)
}
}

if (node.tagType === ElementTypes.ELEMENT) {
const res: DirectiveTransformResult = { props: [] }
const defaultProps = [
Expand Down Expand Up @@ -130,32 +162,9 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
checkDuplicatedValue()
node.children = [createInterpolation(model, model.loc)]
} else if (node.tag === 'select') {
node.children.forEach(option => {
if (option.type === NodeTypes.ELEMENT) {
const plainNode = option as PlainElementNode
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
const value = findValueBinding(plainNode)
plainNode.ssrCodegenNode!.elements.push(
createConditionalExpression(
createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [
createConditionalExpression(
createCallExpression(`Array.isArray`, [model]),
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
model,
value
]),
createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
model,
value
])
)
]),
createSimpleExpression(' selected', true),
createSimpleExpression('', true),
false /* no newline */
)
)
}
node.children.forEach(child => {
if (child.type === NodeTypes.ELEMENT) {
processOption(child as PlainElementNode)
}
})
} else {
Expand Down

0 comments on commit fcf7e50

Please sign in to comment.