diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index 0454c4e6ba7c..dbb1d2c085f1 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -57,16 +57,28 @@ export default function visitEachBlock ( generator, block, state, node ) { } ` ); - block.builders.update.addBlock( deindent` - if ( !${each_block_value}.length && ${each_block_else} ) { - ${each_block_else}.update( changed, ${params} ); - } else if ( !${each_block_value}.length ) { - ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${each_block_else}.mount( ${anchor}.parentNode, ${anchor} ); - } else if ( ${each_block_else} ) { - ${each_block_else}.destroy( true ); - } - ` ); + if ( node.else._block.hasUpdateMethod ) { + block.builders.update.addBlock( deindent` + if ( !${each_block_value}.length && ${each_block_else} ) { + ${each_block_else}.update( changed, ${params} ); + } else if ( !${each_block_value}.length ) { + ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); + ${each_block_else}.mount( ${anchor}.parentNode, ${anchor} ); + } else if ( ${each_block_else} ) { + ${each_block_else}.destroy( true ); + } + ` ); + } else { + block.builders.update.addBlock( deindent` + if ( ${each_block_value}.length ) { + if ( ${each_block_else} ) ${each_block_else}.destroy( true ); + } else if ( !${each_block_else} ) { + ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); + ${each_block_else}.mount( ${anchor}.parentNode, ${anchor} ); + } + ` ); + } + block.builders.destroy.addBlock( deindent` if ( ${each_block_else} ) { diff --git a/src/generators/dom/visitors/Element/Binding.js b/src/generators/dom/visitors/Element/Binding.js index e88fe8df4305..7e405f1965ab 100644 --- a/src/generators/dom/visitors/Element/Binding.js +++ b/src/generators/dom/visitors/Element/Binding.js @@ -4,7 +4,7 @@ import getSetter from '../shared/binding/getSetter.js'; import getStaticAttributeValue from './getStaticAttributeValue.js'; export default function visitBinding ( generator, block, state, node, attribute ) { - const { name, keypath } = flattenReference( attribute.value ); + const { name, keypath, parts } = flattenReference( attribute.value ); const { snippet, contexts, dependencies } = block.contextualise( attribute.value ); if ( dependencies.length > 1 ) throw new Error( 'An unexpected situation arose. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!' ); @@ -17,7 +17,7 @@ export default function visitBinding ( generator, block, state, node, attribute const handler = block.getUniqueName( `${state.parentNode}_${eventName}_handler` ); const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue const type = getStaticAttributeValue( node, 'type' ); - const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, keypath ) : null; + const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, parts.join( '.' ) ) : null; const value = getBindingValue( generator, block, state, node, attribute, isMultipleSelect, bindingGroup, type ); let setter = getSetter({ block, name, keypath, context: '_svelte', attribute, dependencies, value }); diff --git a/test/runtime/samples/binding-input-checkbox-group-outside-each/_config.js b/test/runtime/samples/binding-input-checkbox-group-outside-each/_config.js new file mode 100644 index 000000000000..bff66c903b2a --- /dev/null +++ b/test/runtime/samples/binding-input-checkbox-group-outside-each/_config.js @@ -0,0 +1,78 @@ +const values = [ + { name: 'Alpha' }, + { name: 'Beta' }, + { name: 'Gamma' } +]; + +export default { + data: { + values, + selected: [ values[1] ] + }, + + 'skip-ssr': true, // values are rendered as [object Object] + + html: ` + + + + + + +

Beta

`, + + test ( assert, component, target, window ) { + const inputs = target.querySelectorAll( 'input' ); + assert.equal( inputs[0].checked, false ); + assert.equal( inputs[1].checked, true ); + assert.equal( inputs[2].checked, false ); + + const event = new window.Event( 'change' ); + + inputs[0].checked = true; + inputs[0].dispatchEvent( event ); + + assert.htmlEqual( target.innerHTML, ` + + + + + + +

Alpha, Beta

+ ` ); + + component.set({ selected: [ values[1], values[2] ] }); + assert.equal( inputs[0].checked, false ); + assert.equal( inputs[1].checked, true ); + assert.equal( inputs[2].checked, true ); + + assert.htmlEqual( target.innerHTML, ` + + + + + + +

Beta, Gamma

+ ` ); + } +}; diff --git a/test/runtime/samples/binding-input-checkbox-group-outside-each/main.html b/test/runtime/samples/binding-input-checkbox-group-outside-each/main.html new file mode 100644 index 000000000000..126f7b79c103 --- /dev/null +++ b/test/runtime/samples/binding-input-checkbox-group-outside-each/main.html @@ -0,0 +1,13 @@ + + + + + + +

{{selected.map( function ( value ) { return value.name; }).join( ', ' ) }}

\ No newline at end of file diff --git a/test/runtime/samples/each-block-dynamic-else-static/_config.js b/test/runtime/samples/each-block-dynamic-else-static/_config.js new file mode 100644 index 000000000000..6508c6ba5e14 --- /dev/null +++ b/test/runtime/samples/each-block-dynamic-else-static/_config.js @@ -0,0 +1,27 @@ +export default { + data: { + animals: [ 'alpaca', 'baboon', 'capybara' ] + }, + + html: ` +

alpaca

+

baboon

+

capybara

+ `, + + test ( assert, component, target ) { + component.set({ animals: [] }); + assert.htmlEqual( target.innerHTML, ` +

no animals

+ ` ); + + // trigger an 'update' of the else block, to ensure that + // non-existent update method is not called + component.set({ animals: [] }); + + component.set({ animals: ['wombat'] }); + assert.htmlEqual( target.innerHTML, ` +

wombat

+ ` ); + } +}; diff --git a/test/runtime/samples/each-block-dynamic-else-static/main.html b/test/runtime/samples/each-block-dynamic-else-static/main.html new file mode 100644 index 000000000000..edd88f4705cd --- /dev/null +++ b/test/runtime/samples/each-block-dynamic-else-static/main.html @@ -0,0 +1,5 @@ +{{#each animals as animal}} +

{{animal}}

+{{else}} +

no animals

+{{/each}} \ No newline at end of file