Skip to content

Commit 2b4aa83

Browse files
committed
fix(ssr): handle initial selected state for select with v-model + v-for/v-if option
1 parent 532cfae commit 2b4aa83

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

packages/compiler-ssr/__tests__/ssrVModel.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,62 @@ describe('ssr: v-model', () => {
166166
_push(\`</optgroup></select></div>\`)
167167
}"
168168
`)
169+
170+
expect(
171+
compileWithWrapper(`
172+
<select multiple v-model="model">
173+
<optgroup>
174+
<option v-for="item in items" :value="item">{{item}}</option>
175+
</optgroup>
176+
</select>`).code,
177+
).toMatchInlineSnapshot(`
178+
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
179+
180+
return function ssrRender(_ctx, _push, _parent, _attrs) {
181+
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup><!--[-->\`)
182+
_ssrRenderList(_ctx.items, (item) => {
183+
_push(\`<option\${
184+
_ssrRenderAttr("value", item)
185+
}\${
186+
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
187+
? _ssrLooseContain(_ctx.model, item)
188+
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
189+
}>\${
190+
_ssrInterpolate(item)
191+
}</option>\`)
192+
})
193+
_push(\`<!--]--></optgroup></select></div>\`)
194+
}"
195+
`)
196+
197+
expect(
198+
compileWithWrapper(`
199+
<select multiple v-model="model">
200+
<optgroup>
201+
<option v-if="true" :value="item">{{item}}</option>
202+
</optgroup>
203+
</select>`).code,
204+
).toMatchInlineSnapshot(`
205+
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require("vue/server-renderer")
206+
207+
return function ssrRender(_ctx, _push, _parent, _attrs) {
208+
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup>\`)
209+
if (true) {
210+
_push(\`<option\${
211+
_ssrRenderAttr("value", _ctx.item)
212+
}\${
213+
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
214+
? _ssrLooseContain(_ctx.model, _ctx.item)
215+
: _ssrLooseEqual(_ctx.model, _ctx.item))) ? " selected" : ""
216+
}>\${
217+
_ssrInterpolate(_ctx.item)
218+
}</option>\`)
219+
} else {
220+
_push(\`<!---->\`)
221+
}
222+
_push(\`</optgroup></select></div>\`)
223+
}"
224+
`)
169225
})
170226

171227
test('<input type="radio">', () => {

packages/compiler-ssr/src/transforms/ssrVModel.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,17 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
6565
)
6666
}
6767
} else if (plainNode.tag === 'optgroup') {
68-
plainNode.children.forEach(option =>
69-
processOption(option as PlainElementNode),
70-
)
68+
plainNode.children.forEach(option => {
69+
if (option.type === NodeTypes.ELEMENT) {
70+
processOption(option as PlainElementNode)
71+
} else if (option.type === NodeTypes.FOR) {
72+
option.children.forEach(c => processOption(c as PlainElementNode))
73+
} else if (option.type === NodeTypes.IF) {
74+
option.branches.forEach(b =>
75+
b.children.forEach(c => processOption(c as PlainElementNode)),
76+
)
77+
}
78+
})
7179
}
7280
}
7381

0 commit comments

Comments
 (0)