Skip to content

Commit

Permalink
[BUGFIX release] Default {{each}} key to @Guid or @item based on type.
Browse files Browse the repository at this point in the history
  • Loading branch information
rwjblue committed Jun 16, 2015
1 parent 9c97c78 commit 01a7103
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
7 changes: 1 addition & 6 deletions packages/ember-htmlbars/lib/helpers/each.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,7 @@ import decodeEachKey from "ember-htmlbars/utils/decode-each-key";
items (and reorder the generated DOM elements) based on each item's `id`
property.
There are a few special values for `key`:
* `@index` - The index of the item in the array.
* `@item` - The item in the array itself. This can only be used for arrays of strings
or numbers.
* `@guid` - Generate a unique identifier for each object (uses `Ember.guidFor`).
By default the item's own reference is used.
### {{else}} condition
Expand Down
26 changes: 22 additions & 4 deletions packages/ember-htmlbars/lib/utils/decode-each-key.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,50 @@
import Ember from "ember-metal/core";
import Ember from 'ember-metal/core';
import { get } from "ember-metal/property_get";
import { guidFor } from "ember-metal/utils";

function identity(item) {
let key;
let type = typeof item;

if (type === 'string' || type === 'number') {
key = item;
} else {
key = guidFor(item);
}

return key;
}
export default function decodeEachKey(item, keyPath, index) {
var key;
var key, deprecatedSpecialKey;

switch (keyPath) {
case '@index':
key = index;
break;
case '@guid':
deprecatedSpecialKey = '@guid';
key = guidFor(item);
break;
case '@item':
deprecatedSpecialKey = '@item';
key = item;
break;
case '@identity':
key = identity(item);
break;
default:
if (keyPath) {
key = get(item, keyPath);
} else {
Ember.warn('Using `{{each}}` without specifying a key can lead to unusual behavior. Please specify a `key` that identifies a unique value on each item being iterated. E.g. `{{each model key="@guid" as |item|}}`.');
key = index;
key = identity(item);
}
}

if (typeof key === 'number') {
key = String(key);
}

Ember.deprecate(`Using '${deprecatedSpecialKey}' with the {{each}} helper, is deprecated. Switch to '@identity' or remove 'key=' from your template.`, !deprecatedSpecialKey);

return key;
}
42 changes: 41 additions & 1 deletion packages/ember-htmlbars/tests/helpers/each_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,9 @@ QUnit.test('can specify `@index` to represent the items index in the array being
equal(view.$().text(), '123');
});

QUnit.test('can specify `@guid` to represent the items GUID', function() {
QUnit.test('can specify `@guid` to represent the items GUID [DEPRECATED]', function() {
expectDeprecation(`Using '@guid' with the {{each}} helper, is deprecated. Switch to '@identity' or remove 'key=' from your template.`);

runDestroy(view);
view = EmberView.create({
items: [
Expand All @@ -1243,6 +1245,8 @@ QUnit.test('can specify `@guid` to represent the items GUID', function() {
});

QUnit.test('can specify `@item` to represent primitive items', function() {
expectDeprecation(`Using '@item' with the {{each}} helper, is deprecated. Switch to '@identity' or remove 'key=' from your template.`);

runDestroy(view);
view = EmberView.create({
items: [1, 2, 3],
Expand All @@ -1260,5 +1264,41 @@ QUnit.test('can specify `@item` to represent primitive items', function() {
equal(view.$().text(), 'foobarbaz');
});

QUnit.test('can specify `@identity` to represent primitive items', function() {
runDestroy(view);
view = EmberView.create({
items: [1, 2, 3],
template: compile("{{#each view.items key='@identity' as |item|}}{{item}}{{/each}}")
});

runAppend(view);

equal(view.$().text(), '123');

run(function() {
set(view, 'items', ['foo', 'bar', 'baz']);
});

equal(view.$().text(), 'foobarbaz');
});

QUnit.test('can specify `@identity` to represent mixed object and primitive items', function() {
runDestroy(view);
view = EmberView.create({
items: [1, { id: 2 }, 3],
template: compile("{{#each view.items key='@identity' as |item|}}{{#if item.id}}{{item.id}}{{else}}{{item}}{{/if}}{{/each}}")
});

runAppend(view);

equal(view.$().text(), '123');

run(function() {
set(view, 'items', ['foo', { id: 'bar' }, 'baz']);
});

equal(view.$().text(), 'foobarbaz');
});

testEachWithItem("{{#each foo in bar}}", false);
testEachWithItem("{{#each bar as |foo|}}", true);

0 comments on commit 01a7103

Please sign in to comment.