Skip to content

Commit 57e8fc0

Browse files
thePunderWomandylhunn
authored andcommitted
fix(core): Updates error to use RuntimeError code (#46526)
This updates the iterable differ error to use more up-to-date error codes. PR Close #46526
1 parent f355a24 commit 57e8fc0

File tree

5 files changed

+45
-8
lines changed

5 files changed

+45
-8
lines changed

aio/content/errors/NG2200.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@name Missing Iterable Differ
2+
@category runtime
3+
@shortDescription Cannot find a differ for object in ngFor
4+
5+
@description
6+
`NgFor` could not find an iterable differ for the value passed in. Make sure it's an iterable, like an `Array`.
7+
8+
@debugging
9+
When using ngFor in a template, you must use some type of Iterable, like `Array`, `Set`, `Map`, etc.
10+
If you're trying to iterate over the keys in an object, you should look at the [KeyValue pipe](/api/common/KeyValuePipe) instead.
11+
12+
<!-- links -->
13+
14+
<!-- external links -->
15+
16+
<!-- end links -->

goldens/public-api/common/errors.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export const enum RuntimeErrorCode {
99
// (undocumented)
1010
INVALID_PIPE_ARGUMENT = 2100,
1111
// (undocumented)
12+
NG_FOR_MISSING_DIFFER = 2200,
13+
// (undocumented)
1214
PARENT_NG_SWITCH_NOT_FOUND = 2000
1315
}
1416

packages/common/src/directives/ng_for_of.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef} from '@angular/core';
9+
import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, ɵRuntimeError as RuntimeError} from '@angular/core';
10+
11+
import {RuntimeErrorCode} from '../errors';
12+
13+
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
1014

1115
/**
1216
* @publicApi
@@ -160,7 +164,7 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
160164
*/
161165
@Input()
162166
set ngForTrackBy(fn: TrackByFunction<T>) {
163-
if ((typeof ngDevMode === 'undefined' || ngDevMode) && fn != null && typeof fn !== 'function') {
167+
if (NG_DEV_MODE && fn != null && typeof fn !== 'function') {
164168
// TODO(vicb): use a log service once there is a public one available
165169
if (<any>console && <any>console.warn) {
166170
console.warn(
@@ -209,14 +213,18 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
209213
// React on ngForOf changes only once all inputs have been initialized
210214
const value = this._ngForOf;
211215
if (!this._differ && value) {
212-
if (typeof ngDevMode === 'undefined' || ngDevMode) {
216+
if (NG_DEV_MODE) {
213217
try {
214218
// CAUTION: this logic is duplicated for production mode below, as the try-catch
215219
// is only present in development builds.
216220
this._differ = this._differs.find(value).create(this.ngForTrackBy);
217221
} catch {
218-
throw new Error(`Cannot find a differ supporting object '${value}' of type '${
219-
getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
222+
let errorMessage = `Cannot find a differ supporting object '${value}' of type '` +
223+
`${getTypeName(value)}'. NgFor only supports binding to Iterables, such as Arrays.`;
224+
if (typeof value === 'object') {
225+
errorMessage += ' Did you mean to use the keyvalue pipe?';
226+
}
227+
throw new RuntimeError(RuntimeErrorCode.NG_FOR_MISSING_DIFFER, errorMessage);
220228
}
221229
} else {
222230
// CAUTION: this logic is duplicated for development mode above, as the try-catch

packages/common/src/errors.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ export const enum RuntimeErrorCode {
1414
// NgSwitch errors
1515
PARENT_NG_SWITCH_NOT_FOUND = 2000,
1616
// Pipe errors
17-
INVALID_PIPE_ARGUMENT = 2100
17+
INVALID_PIPE_ARGUMENT = 2100,
18+
// NgForOf errors
19+
NG_FOR_MISSING_DIFFER = 2200,
1820
}

packages/common/test/directives/ng_for_spec.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,22 @@ let thisArg: any;
114114
detectChangesAndExpectText('1;2;3;');
115115
}));
116116

117-
it('should throw on non-iterable ref and suggest using an array', waitForAsync(() => {
117+
it('should throw on non-iterable ref', waitForAsync(() => {
118118
fixture = createTestComponent();
119119

120120
getComponent().items = <any>'whaaa';
121121
expect(() => fixture.detectChanges())
122122
.toThrowError(
123-
/Cannot find a differ supporting object 'whaaa' of type 'string'. NgFor only supports binding to Iterables such as Arrays/);
123+
/NG02200: Cannot find a differ supporting object 'whaaa' of type 'string'. NgFor only supports binding to Iterables, such as Arrays./);
124+
}));
125+
126+
it('should throw on non-iterable ref and suggest using an array ', waitForAsync(() => {
127+
fixture = createTestComponent();
128+
129+
getComponent().items = <any>{'stuff': 'whaaa'};
130+
expect(() => fixture.detectChanges())
131+
.toThrowError(
132+
/NG02200: Cannot find a differ supporting object '\[object Object\]' of type 'object'. NgFor only supports binding to Iterables, such as Arrays. Did you mean to use the keyvalue pipe?/);
124133
}));
125134

126135
it('should throw on ref changing to string', waitForAsync(() => {

0 commit comments

Comments
 (0)