`)
})
+ test('<select v-model>', () => {
+ expect(
+ compileWithWrapper(
+ `<select v-model="model"><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>`
+ ).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><option value=\\"1\\" selected></option><option value=\\"2\\"\${
+ (_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
+ ? _ssrLooseContain(_ctx.model, \\"2\\")
+ : _ssrLooseEqual(_ctx.model, \\"2\\"))) ? \\" selected\\" : \\"\\"
+ }></option></select></div>\`)
+ }"
+ `)
+ })
+
test('<input type="radio">', () => {
expect(
compileWithWrapper(`<input type="radio" value="foo" v-model="bar">`).code
import {
SSR_LOOSE_EQUAL,
SSR_LOOSE_CONTAIN,
- SSR_RENDER_DYNAMIC_MODEL
+ SSR_RENDER_DYNAMIC_MODEL,
+ SSR_INCLUDE_BOOLEAN_ATTR
} from '../runtimeHelpers'
import { DirectiveTransformResult } from 'packages/compiler-core/src/transform'
checkDuplicatedValue()
node.children = [createInterpolation(model, model.loc)]
} else if (node.tag === 'select') {
- // NOOP
- // select relies on client-side directive to set initial selected state.
+ 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 */
+ )
+ )
+ }
+ }
+ })
} else {
context.onError(
createDOMCompilerError(
).toBe(`<input type="radio">`)
})
+ test('select', async () => {
+ expect(
+ await renderToString(
+ createApp({
+ data: () => ({ model: 1 }),
+ template: `<select v-model="model"><option value="0"></option><option value="1"></option></select>`
+ })
+ )
+ ).toBe(
+ `<select><option value="0"></option><option value="1" selected></option></select>`
+ )
+
+ expect(
+ await renderToString(
+ createApp({
+ data: () => ({ model: [0, 1] }),
+ template: `<select multiple v-model="model"><option value="0"></option><option value="1"></option></select>`
+ })
+ )
+ ).toBe(
+ `<select multiple><option value="0" selected></option><option value="1" selected></option></select>`
+ )
+ })
+
test('checkbox', async () => {
expect(
await renderToString(