X Tutup
Skip to content

Commit 49527ab

Browse files
committed
fix(ngFor): give more instructive error when binding to non-iterable
Before, you'd get an error like: ``` EXCEPTION: Cannot find a differ supporting object ‘[object Object]’ in [users in UsersCmp@2:14] ``` Now, you get: ``` EXCEPTION: Cannot find a differ supporting object ‘[object Object]’ of type 'Object'. Did you mean to bind ngFor to an Array? in [users in UsersCmp@2:14] ```
1 parent 0898bca commit 49527ab

File tree

5 files changed

+35
-6
lines changed

5 files changed

+35
-6
lines changed

modules/angular2/src/common/directives/ng_for.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import {
99
EmbeddedViewRef,
1010
TrackByFn
1111
} from 'angular2/core';
12-
import {isPresent, isBlank} from 'angular2/src/facade/lang';
12+
import {isPresent, isBlank, stringify, getTypeNameForDebugging} from 'angular2/src/facade/lang';
1313
import {
1414
DefaultIterableDiffer,
1515
CollectionChangeRecord
1616
} from "../../core/change_detection/differs/default_iterable_differ";
17+
import {BaseException} from "../../facade/exceptions";
1718

1819
/**
1920
* The `NgFor` directive instantiates a template once per item from an iterable. The context for
@@ -77,7 +78,12 @@ export class NgFor implements DoCheck {
7778
set ngForOf(value: any) {
7879
this._ngForOf = value;
7980
if (isBlank(this._differ) && isPresent(value)) {
80-
this._differ = this._iterableDiffers.find(value).create(this._cdr, this._ngForTrackBy);
81+
try {
82+
this._differ = this._iterableDiffers.find(value).create(this._cdr, this._ngForTrackBy);
83+
} catch (e) {
84+
throw new BaseException(
85+
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
86+
}
8187
}
8288
}
8389

modules/angular2/src/core/change_detection/differs/iterable_differs.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
1+
import {isBlank, isPresent, CONST, getTypeNameForDebugging} from 'angular2/src/facade/lang';
22
import {BaseException} from 'angular2/src/facade/exceptions';
33
import {ListWrapper} from 'angular2/src/facade/collection';
44
import {ChangeDetectorRef} from '../change_detector_ref';
@@ -86,7 +86,8 @@ export class IterableDiffers {
8686
if (isPresent(factory)) {
8787
return factory;
8888
} else {
89-
throw new BaseException(`Cannot find a differ supporting object '${iterable}'`);
89+
throw new BaseException(
90+
`Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'`);
9091
}
9192
}
9293
}

modules/angular2/src/facade/lang.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dart:math' as math;
55
import 'dart:convert' as convert;
66
import 'dart:async' show Future, Zone;
77

8-
String getTypeNameForDebugging(Type type) => type.toString();
8+
String getTypeNameForDebugging(Object type) => type.toString();
99

1010
class Math {
1111
static final _random = new math.Random();

modules/angular2/src/facade/lang.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ export interface Type extends Function {}
6262
export interface ConcreteType extends Type { new (...args): any; }
6363

6464
export function getTypeNameForDebugging(type: Type): string {
65-
return type['name'];
65+
if (type['name']) {
66+
return type['name'];
67+
}
68+
return typeof type;
6669
}
6770

6871

modules/angular2/test/common/directives/ng_for_spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from 'angular2/testing_internal';
1515

1616
import {ListWrapper} from 'angular2/src/facade/collection';
17+
import {IS_DART} from 'angular2/src/facade/lang';
1718
import {Component, TemplateRef, ContentChild} from 'angular2/core';
1819
import {NgFor} from 'angular2/src/common/directives/ng_for';
1920
import {NgIf} from 'angular2/src/common/directives/ng_if';
@@ -158,6 +159,24 @@ export function main() {
158159
});
159160
}));
160161

162+
if (!IS_DART) {
163+
it('should throw on non-iterable ref and suggest using an array',
164+
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
165+
tcb.overrideTemplate(TestComponent, TEMPLATE)
166+
.createAsync(TestComponent)
167+
.then((fixture) => {
168+
fixture.debugElement.componentInstance.items = 'whaaa';
169+
try {
170+
fixture.detectChanges()
171+
} catch (e) {
172+
expect(e.message).toContain(
173+
`Cannot find a differ supporting object 'whaaa' of type 'string'. NgFor only supports binding to Iterables such as Arrays.`);
174+
async.done();
175+
}
176+
});
177+
}));
178+
}
179+
161180
it('should throw on ref changing to string',
162181
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
163182
tcb.overrideTemplate(TestComponent, TEMPLATE)

0 commit comments

Comments
 (0)
X Tutup