feat(change_detection): provide error context for change detection errors

This commit is contained in:
vsavkin
2015-07-23 18:01:34 -07:00
parent e744409cb9
commit c2bbda02a1
17 changed files with 147 additions and 36 deletions

View File

@ -7,6 +7,12 @@ import {ProtoRecord} from './proto_record';
import {Locals} from './parser/locals';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
class _Context {
constructor(public element: any, public componentElement: any, public instance: any,
public context: any, public locals: any, public injector: any,
public expression: any) {}
}
export class AbstractChangeDetector implements ChangeDetector {
lightDomChildren: List<any> = [];
shadowDomChildren: List<any> = [];
@ -14,7 +20,7 @@ export class AbstractChangeDetector implements ChangeDetector {
mode: string = null;
ref: ChangeDetectorRef;
constructor(public id: string) { this.ref = new ChangeDetectorRef(this); }
constructor(public id: string, public dispatcher: any) { this.ref = new ChangeDetectorRef(this); }
addChild(cd: ChangeDetector): void {
this.lightDomChildren.push(cd);
@ -83,6 +89,9 @@ export class AbstractChangeDetector implements ChangeDetector {
}
throwError(proto: ProtoRecord, exception: any, stack: any): void {
throw new ChangeDetectionError(proto, exception, stack);
var c = this.dispatcher.getDebugContext(proto.bindingRecord.elementIndex, proto.directiveIndex);
var context = new _Context(c["element"], c["componentElement"], c["directive"], c["context"],
c["locals"], c["injector"], proto.expressionAsString);
throw new ChangeDetectionError(proto, exception, stack, context);
}
}
}

View File

@ -68,8 +68,7 @@ export class ChangeDetectorJITGenerator {
var typeName = _sanitizeName(`ChangeDetector_${this.id}`);
var classDefinition = `
var ${typeName} = function ${typeName}(dispatcher, protos, directiveRecords) {
${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)});
${DISPATCHER_ACCESSOR} = dispatcher;
${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)}, dispatcher);
${PROTOS_ACCESSOR} = protos;
${DIRECTIVES_ACCESSOR} = directiveRecords;
${LOCALS_ACCESSOR} = null;

View File

@ -129,7 +129,7 @@ export class ChangeDetectionUtil {
}
static throwOnChange(proto: ProtoRecord, change) {
throw new ExpressionChangedAfterItHasBeenChecked(proto, change);
throw new ExpressionChangedAfterItHasBeenChecked(proto, change, null);
}
static throwDehydrated() { throw new DehydratedException(); }

View File

@ -20,9 +20,9 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
alreadyChecked: boolean = false;
private pipes: Pipes = null;
constructor(id: string, private changeControlStrategy: string, private dispatcher: any,
constructor(id: string, private changeControlStrategy: string, dispatcher: any,
private protos: List<ProtoRecord>, private directiveRecords: List<any>) {
super(id);
super(id, dispatcher);
this.values = ListWrapper.createFixedSize(protos.length + 1);
this.localPipes = ListWrapper.createFixedSize(protos.length + 1);
this.prevContexts = ListWrapper.createFixedSize(protos.length + 1);

View File

@ -2,7 +2,7 @@ import {ProtoRecord} from './proto_record';
import {BaseException} from "angular2/src/facade/lang";
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
constructor(proto: ProtoRecord, change: any) {
constructor(proto: ProtoRecord, change: any, context: any) {
super(`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`);
}
@ -11,9 +11,9 @@ export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
export class ChangeDetectionError extends BaseException {
location: string;
constructor(proto: ProtoRecord, originalException: any, originalStack: any) {
super(`${originalException} in [${proto.expressionAsString}]`, originalException,
originalStack);
constructor(proto: ProtoRecord, originalException: any, originalStack: any, context: any) {
super(`${originalException} in [${proto.expressionAsString}]`, originalException, originalStack,
context);
this.location = proto.expressionAsString;
}
}