diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 290c1b0d6ee3..4609d9548024 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -538,15 +538,19 @@ export default class ElementWrapper extends Wrapper { } addAttributes(block: Block) { + // Get all the class dependencies first + this.attributes.forEach((attribute: Attribute) => { + if (attribute.node.name === 'class' && attribute.node.isDynamic) { + this.classDependencies.push(...attribute.node.dependencies); + } + }); + if (this.node.attributes.find(attr => attr.type === 'Spread')) { this.addSpreadAttributes(block); return; } this.attributes.forEach((attribute: Attribute) => { - if (attribute.node.name === 'class' && attribute.node.isDynamic) { - this.classDependencies.push(...attribute.node.dependencies); - } attribute.render(block); }); } @@ -934,4 +938,4 @@ export default class ElementWrapper extends Wrapper { ); } } -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Element.ts b/src/compile/render-ssr/handlers/Element.ts index d7bc823be2d8..acda204215ec 100644 --- a/src/compile/render-ssr/handlers/Element.ts +++ b/src/compile/render-ssr/handlers/Element.ts @@ -84,6 +84,9 @@ export default function(node, renderer, options) { ) { // a boolean attribute with one non-Text chunk args.push(`{ ${quoteNameIfNecessary(attribute.name)}: ${attribute.chunks[0].snippet} }`); + } else if (attribute.name === 'class' && classExpr) { + // Add class expression + args.push(`{ ${quoteNameIfNecessary(attribute.name)}: [\`${stringifyAttribute(attribute)}\`, \`\${${classExpr}}\`].join(' ').trim() }`); } else { args.push(`{ ${quoteNameIfNecessary(attribute.name)}: \`${stringifyAttribute(attribute)}\` }`); } @@ -159,4 +162,4 @@ function stringifyAttribute(attribute: Attribute) { return '${@escape(' + chunk.snippet + ')}'; }) .join(''); -} \ No newline at end of file +} diff --git a/test/runtime/samples/class-with-dynamic-attribute-and-spread/_config.js b/test/runtime/samples/class-with-dynamic-attribute-and-spread/_config.js new file mode 100644 index 000000000000..a99a9a9d1e63 --- /dev/null +++ b/test/runtime/samples/class-with-dynamic-attribute-and-spread/_config.js @@ -0,0 +1,22 @@ +export default { + data: { + myClass: 'one two', + attributes: { + role: 'button' + } + }, + html: `
`, + + test ( assert, component, target, window ) { + component.set({ + attributes: { + 'aria-label': 'Test' + }, + myClass: 'one' + }); + + assert.htmlEqual( target.innerHTML, ` + + ` ); + } +}; diff --git a/test/runtime/samples/class-with-dynamic-attribute-and-spread/main.html b/test/runtime/samples/class-with-dynamic-attribute-and-spread/main.html new file mode 100644 index 000000000000..b87c1c7b3cf6 --- /dev/null +++ b/test/runtime/samples/class-with-dynamic-attribute-and-spread/main.html @@ -0,0 +1 @@ + diff --git a/test/runtime/samples/class-with-spread/_config.js b/test/runtime/samples/class-with-spread/_config.js new file mode 100644 index 000000000000..c26a534d2a57 --- /dev/null +++ b/test/runtime/samples/class-with-spread/_config.js @@ -0,0 +1,22 @@ +export default { + data: { + myClass: 'one two', + attributes: { + role: 'button' + } + }, + html: ``, + + test ( assert, component, target, window ) { + component.set({ + attributes: { + 'aria-label': 'Test' + }, + myClass: 'one' + }); + + assert.htmlEqual( target.innerHTML, ` + + ` ); + } +}; diff --git a/test/runtime/samples/class-with-spread/main.html b/test/runtime/samples/class-with-spread/main.html new file mode 100644 index 000000000000..dab73757c9a9 --- /dev/null +++ b/test/runtime/samples/class-with-spread/main.html @@ -0,0 +1 @@ +