diff --git a/compiler/generate/visitors/EachBlock.js b/compiler/generate/visitors/EachBlock.js index 089ab59876..845105160f 100644 --- a/compiler/generate/visitors/EachBlock.js +++ b/compiler/generate/visitors/EachBlock.js @@ -5,8 +5,11 @@ export default { enter ( generator, node ) { const i = generator.counters.each++; const name = `eachBlock_${i}`; + const elseName = `${name}_else`; const iterations = `${name}_iterations`; const renderer = `renderEachBlock_${i}`; + const renderElse = `${renderer}_else`; + const { params } = generator.current; const listName = `${name}_value`; @@ -21,12 +24,21 @@ export default { generator.current.initStatements.push( deindent` var ${name}_value = ${snippet}; var ${iterations} = []; + ${node.else ? `var ${elseName} = null;` : ''} for ( var i = 0; i < ${name}_value.length; i += 1 ) { - ${iterations}[i] = ${renderer}( ${generator.current.params}, ${listName}, ${listName}[i], i, component ); + ${iterations}[i] = ${renderer}( ${params}, ${listName}, ${listName}[i], i, component ); ${!isToplevel ? `${iterations}[i].mount( ${anchor}.parentNode, ${anchor} );` : ''} } ` ); + if ( node.else ) { + generator.current.initStatements.push( deindent` + if ( !${name}_value.length ) { + ${elseName} = ${renderElse}( ${params}, component ); + ${!isToplevel ? `${elseName}.mount( ${anchor}.parentNode, ${anchor} );` : ''} + } + ` ); + } if ( isToplevel ) { generator.current.mountStatements.push( deindent` @@ -34,6 +46,13 @@ export default { ${iterations}[i].mount( ${anchor}.parentNode, ${anchor} ); } ` ); + if ( node.else ) { + generator.current.mountStatements.push( deindent` + if ( ${elseName} ) { + ${elseName}.mount( ${anchor}.parentNode, ${anchor} ); + } + ` ); + } } generator.current.updateStatements.push( deindent` @@ -41,10 +60,10 @@ export default { for ( var i = 0; i < ${name}_value.length; i += 1 ) { if ( !${iterations}[i] ) { - ${iterations}[i] = ${renderer}( ${generator.current.params}, ${listName}, ${listName}[i], i, component ); + ${iterations}[i] = ${renderer}( ${params}, ${listName}, ${listName}[i], i, component ); ${iterations}[i].mount( ${anchor}.parentNode, ${anchor} ); } else { - ${iterations}[i].update( changed, ${generator.current.params}, ${listName}, ${listName}[i], i ); + ${iterations}[i].update( changed, ${params}, ${listName}, ${listName}[i], i ); } } @@ -54,12 +73,51 @@ export default { ${iterations}.length = ${listName}.length; ` ); + if ( node.else ) { + generator.current.updateStatements.push( deindent` + if ( !${name}_value.length && ${elseName} ) { + ${elseName}.update( changed, ${params} ); + } else if ( !${name}_value.length ) { + ${elseName} = ${renderElse}( ${params}, component ); + ${elseName}.mount( ${anchor}.parentNode, ${anchor} ); + } else if ( ${elseName} ) { + ${elseName}.teardown( true ); + } + ` ); + } generator.current.teardownStatements.push( deindent` for ( var i = 0; i < ${iterations}.length; i += 1 ) { ${iterations}[i].teardown( ${isToplevel ? 'detach' : 'false'} ); } ` ); + if ( node.else ) { + generator.current.teardownStatements.push( deindent` + if ( ${elseName} ) { + ${elseName}.teardown( ${isToplevel ? 'detach' : 'false'} ); + } + ` ); + } + + if ( node.else ) { + generator.push({ + useAnchor: false, + name: renderElse, + target: 'target', + localElementDepth: 0, + + initStatements: [], + mountStatements: [], + updateStatements: [], + detachStatements: [], + teardownStatements: [], + + counter: counter() + }); + node.else.children.forEach( generator.visit ); + generator.addRenderer( generator.current ); + generator.pop(); + } const indexNames = Object.assign( {}, generator.current.indexNames ); const indexName = indexNames[ node.context ] = ( node.index || `${node.context}__index` ); @@ -76,7 +134,7 @@ export default { const contextDependencies = Object.assign( {}, generator.current.contextDependencies ); contextDependencies[ node.context ] = dependencies; - const params = generator.current.params + `, ${listName}, ${node.context}, ${indexName}`; + const blockParams = generator.current.params + `, ${listName}, ${node.context}, ${indexName}`; generator.push({ useAnchor: false, @@ -92,7 +150,7 @@ export default { indexNames, listNames, - params, + params: blockParams, initStatements: [], mountStatements: [], diff --git a/test/compiler/each-block-else/_config.js b/test/compiler/each-block-else/_config.js new file mode 100644 index 0000000000..313b7fa7e3 --- /dev/null +++ b/test/compiler/each-block-else/_config.js @@ -0,0 +1,17 @@ +export default { + data: { + animals: [ 'alpaca', 'baboon', 'capybara' ], + foo: 'something else' + }, + html: 'before\n

alpaca

baboon

capybara

\nafter', + test ( assert, component, target ) { + component.set({ animals: [] }); + assert.htmlEqual( target.innerHTML, 'before\n

no animals, but rather something else

\nafter' ); + + component.set({ foo: 'something other' }); + assert.htmlEqual( target.innerHTML, 'before\n

no animals, but rather something other

\nafter' ); + + component.set({ animals: ['wombat'] }); + assert.htmlEqual( target.innerHTML, 'before\n

wombat

\nafter' ); + } +}; diff --git a/test/compiler/each-block-else/main.html b/test/compiler/each-block-else/main.html new file mode 100644 index 0000000000..6c13e5fb23 --- /dev/null +++ b/test/compiler/each-block-else/main.html @@ -0,0 +1,7 @@ +before +{{#each animals as animal}} +

{{animal}}

+{{else}} +

no animals, but rather {{foo}}

+{{/each}} +after