X Tutup
Skip to content

Commit c2efa23

Browse files
committed
fix(change_detection): throw ChangeDetectionError in JIT mode
1 parent d277442 commit c2efa23

File tree

8 files changed

+54
-31
lines changed

8 files changed

+54
-31
lines changed

modules/angular2/src/change_detection/abstract_change_detector.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {isPresent} from 'angular2/src/facade/lang';
22
import {List, ListWrapper} from 'angular2/src/facade/collection';
33
import {ChangeDetectorRef} from './change_detector_ref';
44
import {ChangeDetector} from './interfaces';
5+
import {ChangeDetectionError} from './exceptions';
6+
import {ProtoRecord} from './proto_record';
57
import {Locals} from './parser/locals';
68
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
79

@@ -79,4 +81,8 @@ export class AbstractChangeDetector implements ChangeDetector {
7981
c = c.parent;
8082
}
8183
}
84+
85+
throwError(proto: ProtoRecord, exception: any, stack: any): void {
86+
throw new ChangeDetectionError(proto, exception, stack);
87+
}
8288
}

modules/angular2/src/change_detection/change_detection_jit_generator.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var IS_CHANGED_LOCAL = "isChanged";
2828
var CHANGES_LOCAL = "changes";
2929
var LOCALS_ACCESSOR = "this.locals";
3030
var MODE_ACCESSOR = "this.mode";
31-
var CURRENT_PROTO = "currentProto";
31+
var CURRENT_PROTO = "this.currentProto";
3232
var ALREADY_CHECKED_ACCESSOR = "this.alreadyChecked";
3333

3434

@@ -74,6 +74,7 @@ export class ChangeDetectorJITGenerator {
7474
${PROTOS_ACCESSOR} = protos;
7575
${DIRECTIVES_ACCESSOR} = directiveRecords;
7676
${LOCALS_ACCESSOR} = null;
77+
${CURRENT_PROTO} = null;
7778
${ALREADY_CHECKED_ACCESSOR} = false;
7879
${this._genFieldDefinitions()}
7980
}
@@ -84,19 +85,28 @@ export class ChangeDetectorJITGenerator {
8485
if (!this.hydrated()) {
8586
${UTIL}.throwDehydrated();
8687
}
88+
try {
89+
this.__detectChangesInRecords(throwOnChange);
90+
} catch (e) {
91+
this.throwError(${CURRENT_PROTO}, e, e.stack);
92+
}
93+
}
94+
95+
${typeName}.prototype.__detectChangesInRecords = function(throwOnChange) {
96+
${CURRENT_PROTO} = null;
97+
8798
${this._genLocalDefinitions()}
8899
${this._genChangeDefinitions()}
89100
var ${IS_CHANGED_LOCAL} = false;
90-
var ${CURRENT_PROTO};
91101
var ${CHANGES_LOCAL} = null;
92-
102+
93103
context = ${CONTEXT_ACCESSOR};
94-
104+
95105
${this.records.map((r) => this._genRecord(r)).join("\n")}
96-
106+
97107
${ALREADY_CHECKED_ACCESSOR} = true;
98108
}
99-
109+
100110
${typeName}.prototype.callOnAllChangesDone = function() {
101111
${this._genCallOnAllChangesDoneBody()}
102112
}

modules/angular2/src/change_detection/dynamic_change_detector.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import {ChangeDetectionUtil, SimpleChange, uninitialized} from './change_detecti
1010

1111
import {ProtoRecord, RecordType} from './proto_record';
1212

13-
import {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './exceptions';
14-
1513
export class DynamicChangeDetector extends AbstractChangeDetector {
1614
locals: Locals = null;
1715
values: List<any>;
@@ -149,7 +147,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
149147
return this._referenceCheck(proto, throwOnChange);
150148
}
151149
} catch (e) {
152-
throw new ChangeDetectionError(proto, e);
150+
this.throwError(proto, e, e.stack);
153151
}
154152
}
155153

modules/angular2/src/change_detection/exceptions.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,20 @@ import {ProtoRecord} from './proto_record';
22
import {BaseException} from "angular2/src/facade/lang";
33

44
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
5-
message: string;
6-
75
constructor(proto: ProtoRecord, change: any) {
8-
super();
9-
this.message =
10-
`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
11-
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`;
6+
super(`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
7+
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`);
128
}
13-
14-
toString(): string { return this.message; }
159
}
1610

1711
export class ChangeDetectionError extends BaseException {
18-
message: string;
1912
location: string;
2013

21-
constructor(proto: ProtoRecord, public originalException: any) {
22-
super();
14+
constructor(proto: ProtoRecord, originalException: any, originalStack: any) {
15+
super(`${originalException} in [${proto.expressionAsString}]`, originalException,
16+
originalStack);
2317
this.location = proto.expressionAsString;
24-
this.message = `${this.originalException} in [${this.location}]`;
2518
}
26-
27-
toString(): string { return this.message; }
2819
}
2920

3021
export class DehydratedException extends BaseException {

modules/angular2/src/transform/template_compiler/change_detector_codegen.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class _CodegenState {
131131
$_DIRECTIVES_ACCESSOR;
132132
dynamic $_LOCALS_ACCESSOR = null;
133133
dynamic $_ALREADY_CHECKED_ACCESSOR = false;
134+
dynamic $_CURRENT_PROTO = null;
134135
${_allFields().map((f) {
135136
if (f == _CONTEXT_ACCESSOR) {
136137
return '$_contextTypeName $f = null;';
@@ -148,18 +149,26 @@ class _CodegenState {
148149
if (!hydrated()) {
149150
$_UTIL.throwDehydrated();
150151
}
152+
try {
153+
this.__detectChangesInRecords(throwOnChange);
154+
} catch (e, s) {
155+
this.throwError($_CURRENT_PROTO, e, s);
156+
}
157+
}
158+
159+
void __detectChangesInRecords(throwOnChange) {
151160
${_genLocalDefinitions()}
152161
${_genChangeDefinitons()}
153162
var $_IS_CHANGED_LOCAL = false;
154-
var $_CURRENT_PROTO;
163+
$_CURRENT_PROTO = null;
155164
var $_CHANGES_LOCAL = null;
156165
157166
context = $_CONTEXT_ACCESSOR;
158167
${_records.map(_genRecord).join('')}
159168
160169
$_ALREADY_CHECKED_ACCESSOR = true;
161170
}
162-
171+
163172
void callOnAllChangesDone() {
164173
${_getCallOnAllChangesDoneBody()}
165174
}

modules/angular2/test/change_detection/change_detector_config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,5 +309,6 @@ var _availableDefinitions = [
309309
'sayHi("Jim")',
310310
'a()(99)',
311311
'a.sayHi("Jim")',
312-
'passThrough([12])'
312+
'passThrough([12])',
313+
'invalidFn(1)'
313314
];

modules/angular2/test/change_detection/change_detector_spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,16 +542,15 @@ export function main() {
542542
});
543543
});
544544

545-
// TODO vsavkin: implement it
546545
describe('error handling', () => {
547-
xit('should wrap exceptions into ChangeDetectionError', () => {
548-
var val = _createChangeDetector('invalidProp');
546+
it('should wrap exceptions into ChangeDetectionError', () => {
547+
var val = _createChangeDetector('invalidFn(1)');
549548
try {
550549
val.changeDetector.detectChanges();
551550
throw new BaseException('fail');
552551
} catch (e) {
553552
expect(e).toBeAnInstanceOf(ChangeDetectionError);
554-
expect(e.location).toEqual('invalidProp in someComponent');
553+
expect(e.location).toEqual('invalidFn(1) in location');
555554
}
556555
});
557556
});

modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
3232
final _gen.List<_gen.DirectiveRecord> _directiveRecords;
3333
dynamic _locals = null;
3434
dynamic _alreadyChecked = false;
35+
dynamic currentProto = null;
3536
MyComponent _context = null;
3637
dynamic _myNum0 = _gen.ChangeDetectionUtil.uninitialized();
3738
dynamic _interpolate1 = _gen.ChangeDetectionUtil.uninitialized();
@@ -44,14 +45,22 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
4445
if (!hydrated()) {
4546
_gen.ChangeDetectionUtil.throwDehydrated();
4647
}
48+
try {
49+
this.__detectChangesInRecords(throwOnChange);
50+
} catch (e, s) {
51+
this.throwError(currentProto, e, s);
52+
}
53+
}
54+
55+
void __detectChangesInRecords(throwOnChange) {
4756
var context = null;
4857
var myNum0 = null;
4958
var interpolate1 = null;
5059
var change_context = false;
5160
var change_myNum0 = false;
5261
var change_interpolate1 = false;
5362
var isChanged = false;
54-
var currentProto;
63+
currentProto = null;
5564
var changes = null;
5665

5766
context = _context;

0 commit comments

Comments
 (0)
X Tutup