diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index da3353f577..5a427c94c6 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -115,7 +115,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea const value = block.getUniqueName( 'value' ); const key = block.getUniqueName( 'key' ); const lookup = block.getUniqueName( `${each_block}_lookup` ); - const _lookup = block.getUniqueName( `_${each_block}_lookup` ); + const keys = block.getUniqueName( `${each_block}_keys` ); const iteration = block.getUniqueName( `${each_block}_iteration` ); const _iterations = block.getUniqueName( `_${each_block}_iterations` ); @@ -142,19 +142,40 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea const consequent = node._block.hasUpdateMethod ? deindent` - ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ]; - ${_lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + ${_iterations}[${i}] = ${lookup}[ ${key} ] = ${lookup}[ ${key} ]; + ${lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); ` : - `${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ];`; + `${_iterations}[${i}] = ${lookup}[ ${key} ] = ${lookup}[ ${key} ];`; const parentNode = state.parentNode || `${anchor}.parentNode`; const hasIntros = node._block.hasIntroMethod; + const destroy = node._block.hasOutroMethod ? + deindent` + function outro ( key ) { + ${lookup}[ key ].outro( function () { + ${lookup}[ key ].destroy( true ); + ${lookup}[ key ] = null; + }); + } + + for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { + ${key} = ${iterations}[${i}].key; + if ( !${keys}[ ${key} ] ) outro( ${key} ); + } + ` : + deindent` + for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { + var ${iteration} = ${iterations}[${i}]; + if ( !${keys}[ ${iteration}.key ] ) ${iteration}.destroy( true ); + } + `; + block.builders.update.addBlock( deindent` var ${each_block_value} = ${snippet}; var ${_iterations} = []; - var ${_lookup} = Object.create( null ); + var ${keys} = Object.create( null ); var ${fragment} = document.createDocumentFragment(); @@ -162,12 +183,13 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { var ${value} = ${each_block_value}[${i}]; var ${key} = ${value}.${node.key}; + ${keys}[ ${key} ] = true; if ( ${lookup}[ ${key} ] ) { ${consequent} ${hasIntros && `${_iterations}[${i}].mount( ${fragment}, null );`} } else { - ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); + ${_iterations}[${i}] = ${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); ${hasIntros && `${_iterations}[${i}].intro( ${fragment}, null );`} } @@ -175,17 +197,11 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea } // remove old iterations - for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - var ${iteration} = ${iterations}[${i}]; - if ( !${_lookup}[ ${iteration}.key ] ) { - ${iteration}.destroy( true ); - } - } + ${destroy} ${parentNode}.insertBefore( ${fragment}, ${anchor} ); ${iterations} = ${_iterations}; - ${lookup} = ${_lookup}; ` ); } diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 17b22c9a50..c0a8092727 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -39,7 +39,6 @@ function create_main_fragment ( state, component ) { } destroyEach( each_block_iterations, true, each_block_value.length ); - each_block_iterations.length = each_block_value.length; } diff --git a/test/runtime/samples/transition-js-each-block-keyed-outro/_config.js b/test/runtime/samples/transition-js-each-block-keyed-outro/_config.js new file mode 100644 index 0000000000..d40e9a3a06 --- /dev/null +++ b/test/runtime/samples/transition-js-each-block-keyed-outro/_config.js @@ -0,0 +1,25 @@ +export default { + data: { + things: [ + { name: 'a' }, + { name: 'b' }, + { name: 'c' } + ] + }, + + test ( assert, component, target, window, raf ) { + const divs = target.querySelectorAll( 'div' ); + + component.set({ + things: [ + { name: 'a' }, + { name: 'c' } + ] + }); + + raf.tick( 50 ); + assert.equal( divs[0].foo, undefined ); + assert.equal( divs[1].foo, 0.5 ); + assert.equal( divs[2].foo, undefined ); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-block-keyed-outro/main.html b/test/runtime/samples/transition-js-each-block-keyed-outro/main.html new file mode 100644 index 0000000000..2e73512529 --- /dev/null +++ b/test/runtime/samples/transition-js-each-block-keyed-outro/main.html @@ -0,0 +1,18 @@ +{{#each things as thing @name}} +