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

@ -128,7 +128,7 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
DirectiveResolver,
Parser,
Lexer,
bind(ExceptionHandler).toFactory(() => new ExceptionHandler(DOM)),
bind(ExceptionHandler).toFactory(() => new ExceptionHandler(DOM), []),
bind(XHR).toValue(new XHRImpl()),
ComponentUrlMapper,
UrlResolver,

View File

@ -496,10 +496,9 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
private _debugContext(): any {
var p = this._preBuiltObjects;
var element = isPresent(p.elementRef) ? p.elementRef.nativeElement : null;
var hostRef = p.view.getHostElement();
var componentElement = isPresent(hostRef) ? hostRef.nativeElement : null;
return new _Context(element, componentElement, this._injector);
var index = p.elementRef.boundElementIndex - p.view.elementOffset;
var c = this._preBuiltObjects.view.getDebugContext(index, null);
return new _Context(c["element"], c["componentElement"], c["injector"]);
}
private _reattachInjectors(imperativelyCreatedInjector: Injector): void {
@ -573,6 +572,8 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
getComponent(): any { return this._strategy.getComponent(); }
getInjector(): Injector { return this._injector; }
getElementRef(): ElementRef { return this._preBuiltObjects.elementRef; }
getViewContainerRef(): ViewContainerRef {

View File

@ -1,4 +1,11 @@
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
import {
ListWrapper,
MapWrapper,
Map,
StringMapWrapper,
List,
StringMap
} from 'angular2/src/facade/collection';
import {
AST,
Locals,
@ -202,7 +209,36 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
getHostElement(): ElementRef {
var boundElementIndex = this.mainMergeMapping.hostElementIndicesByViewIndex[this.viewOffset];
return this.elementRefs[boundElementIndex];
return isPresent(boundElementIndex) ? this.elementRefs[boundElementIndex] : null;
}
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): StringMap<string, any> {
try {
var offsettedIndex = this.elementOffset + elementIndex;
var hasRefForIndex = offsettedIndex < this.elementRefs.length;
var elementRef = hasRefForIndex ? this.elementRefs[this.elementOffset + elementIndex] : null;
var host = this.getHostElement();
var ei = hasRefForIndex ? this.elementInjectors[this.elementOffset + elementIndex] : null;
var element = isPresent(elementRef) ? elementRef.nativeElement : null;
var componentElement = isPresent(host) ? host.nativeElement : null;
var directive = isPresent(directiveIndex) ? this.getDirectiveFor(directiveIndex) : null;
var injector = isPresent(ei) ? ei.getInjector() : null;
return {
element: element,
componentElement: componentElement,
directive: directive,
context: this.context,
locals: _localsToStringMap(this.locals),
injector: injector
};
} catch (e) {
// TODO: vsavkin log the exception once we have a good way to log errors and warnings
// if an error happens during getting the debug context, we return an empty map.
return {};
}
}
getDetectorFor(directive: DirectiveIndex): any {
@ -252,6 +288,16 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
}
}
function _localsToStringMap(locals: Locals): StringMap<string, any> {
var res = {};
var c = locals;
while (isPresent(c)) {
res = StringMapWrapper.merge(res, MapWrapper.toStringMap(c.current));
c = c.parent;
}
return res;
}
/**
*
*/

View File

@ -50,7 +50,7 @@ export class ExceptionHandler {
if (isPresent(stackTrace) && isBlank(originalStack)) {
this.logger.log("STACKTRACE:");
this.logger.log(this._longStackTrace(stackTrace))
this.logger.log(this._longStackTrace(stackTrace));
}
if (isPresent(reason)) {