8000 fix(compiler-ssr): add selected option attribute from select value by alex-snezhko · Pull Request #13539 · vuejs/core · GitHub
[go: up one dir, main page]

Skip to content

fix(compiler-ssr): add selected option attribute from select value #13539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix: prioritize v-model over value
  • Loading branch information
alex-snezhko committed Jun 28, 2025
commit abc4649c4f99fa8e4275be1bc1ec6eb065125a14
18 changes: 18 additions & 0 deletions packages/compiler-ssr/__tests__/ssrVModel.spec.ts
8000
Original file line numberDiff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ describe('ssr: v-model', () => {
}"
`)

expect(
compileWithWrapper(
`<select v-model="model" value="2"><option value="1"></option></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><option value="1"\${
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
? _ssrLooseContain(_ctx.model, "1")
: _ssrLooseEqual(_ctx.model, "1"))) ? " selected" : ""
}></option></select></div>\`)
}"
`)

expect(
compileWithWrapper(
`<select multiple v-model="model"><option value="1" selected></option><option value="2"></option></select>`,
Expand Down
41 changes: 24 additions & 17 deletions packages/compiler-ssr/src/transforms/ssrTransformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
const needTagForRuntime =
node.tag === 'textarea' || node.tag.indexOf('-') > 0

const hasVModel = node.props.some(
p => p.type === NodeTypes.DIRECTIVE && p.name === 'model',
)

// v-bind="obj", v-bind:[key] and custom directives can potentially
// overwrite other static attrs and can affect final rendering result,
// so when they are present we need to bail out to full `renderAttrs`
Expand Down Expand Up @@ -141,21 +145,24 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
)
}
} else if (node.tag === 'select') {
// <select> with dynamic v-bind. We don't know if the final props
// will contain .value, so we will have to do something special:
// assign the merged props to a temp variable, and check whether
// it contains value (if yes, mark options selected).
const tempId = `_temp${context.temps++}`
propsExp.arguments = [
createAssignmentExpression(
createSimpleExpression(tempId, false),
mergedProps,
),
]
processSelectChildren(context, node.children, {
type: 'dynamicVBind',
tempId,
})
// v-model takes priority over value
if (!hasVModel) {
// <select> with dynamic v-bind. We don't know if the final props
// will contain .value, so we will have to do something special:
// assign the merged props to a temp variable, and check whether
// it contains value (if yes, mark options selected).
const tempId = `_temp${context.temps++}`
propsExp.arguments = [
createAssignmentExpression(
createSimpleExpression(tempId, false),
mergedProps,
),
]
processSelectChildren(context, node.children, {
type: 'dynamicVBind',
tempId,
})
}
} else if (node.tag === 'input') {
// <input v-bind="obj" v-model>
// we need to determine the props to render for the dynamic v-model
Expand Down Expand Up @@ -245,7 +252,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
node.children = [createInterpolation(prop.exp, prop.loc)]
}
} else if (isTagWithValueBind(node, 'select', prop) && prop.exp) {
if (!needMergeProps) {
if (!needMergeProps && !hasVModel) {
processSelectChildren(context, node.children, {
type: 'dynamicValue',
value: prop.exp,
Expand Down Expand Up @@ -351,7 +358,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
if (node.tag === 'textarea' && name === 'value' && prop.value) {
rawChildrenMap.set(node, escapeHtml(prop.value.content))
} else if (node.tag === 'select' && name === 'value' && prop.value) {
if (!needMergeProps) {
if (!needMergeProps && !hasVModel) {
processSelectChildren(context, node.children, {
type: 'staticValue',
value: prop.value.content,
Expand Down
0