diff --git a/packages/ember-htmlbars/lib/helpers/each.js b/packages/ember-htmlbars/lib/helpers/each.js index 21966202180..08d5fee3fe8 100644 --- a/packages/ember-htmlbars/lib/helpers/each.js +++ b/packages/ember-htmlbars/lib/helpers/each.js @@ -1,4 +1,5 @@ import Ember from 'ember-metal/core'; +import Error from 'ember-metal/error'; import normalizeSelf from 'ember-htmlbars/utils/normalize-self'; import shouldDisplay from 'ember-views/streams/should_display'; import decodeEachKey from 'ember-htmlbars/utils/decode-each-key'; @@ -79,6 +80,7 @@ export default function eachHelper(params, hash, blocks) { } if (shouldDisplay(list)) { + let seenKeys = {}; forEach(list, (item, i) => { var self; if (blocks.template.arity === 0) { @@ -86,6 +88,11 @@ export default function eachHelper(params, hash, blocks) { } var key = decodeEachKey(item, keyPath, i); + if (seenKeys[key] === true) { + throw new Error(`Duplicate key found ('${key}') for '{{each}}' helper, please use a unique key or switch to '{{#each model key="@index"}}{{/each}}'.`); + } else { + seenKeys[key] = true; + } blocks.template.yieldItem(key, [item, i], self); }); } else if (blocks.inverse.yield) { diff --git a/packages/ember-htmlbars/tests/helpers/each_test.js b/packages/ember-htmlbars/tests/helpers/each_test.js index 0466a04d66e..3496b077a03 100644 --- a/packages/ember-htmlbars/tests/helpers/each_test.js +++ b/packages/ember-htmlbars/tests/helpers/each_test.js @@ -1302,5 +1302,39 @@ QUnit.test('can specify `@identity` to represent mixed object and primitive item equal(view.$().text(), 'foobarbaz'); }); +QUnit.test('duplicate keys trigger a useful error (temporary until we can deal with this properly in HTMLBars)', function() { + runDestroy(view); + view = EmberView.create({ + items: ['a', 'a', 'a'], + template: compile('{{#each view.items as |item|}}{{item}}{{/each}}') + }); + + throws( + function() { + runAppend(view); + }, + `Duplicate key found ('a') for '{{each}}' helper, please use a unique key or switch to '{{#each model key="@index"}}{{/each}}'.` + ); +}); + +QUnit.test('pushing a new duplicate key will trigger a useful error (temporary until we can deal with this properly in HTMLBars)', function() { + runDestroy(view); + view = EmberView.create({ + items: A(['a', 'b', 'c']), + template: compile('{{#each view.items as |item|}}{{item}}{{/each}}') + }); + + runAppend(view); + + throws( + function() { + run(function() { + view.get('items').pushObject('a'); + }); + }, + `Duplicate key found ('a') for '{{each}}' helper, please use a unique key or switch to '{{#each model key="@index"}}{{/each}}'.` + ); +}); + testEachWithItem('{{#each foo in bar}}', false); testEachWithItem('{{#each bar as |foo|}}', true);