fix(Compiler): Catch exceptions in the logging of binding update

fixes #9994
This commit is contained in:
Victor Berchet 2016-07-12 10:26:54 -07:00
parent b4ea0b1601
commit 27436270fd
5 changed files with 48 additions and 28 deletions

View File

@ -193,13 +193,13 @@ export enum BuiltinVar {
}
export class ReadVarExpr extends Expression {
public name: any /** TODO #9100 */;
public name: string;
public builtin: BuiltinVar;
constructor(name: string|BuiltinVar, type: Type = null) {
super(type);
if (isString(name)) {
this.name = <string>name;
this.name = name;
this.builtin = null;
} else {
this.name = null;
@ -270,7 +270,7 @@ export class InvokeMethodExpr extends Expression {
type: Type = null) {
super(type);
if (isString(method)) {
this.name = <string>method;
this.name = method;
this.builtin = null;
} else {
this.name = null;

View File

@ -11,19 +11,13 @@ import * as cdAst from '../expression_parser/ast';
import {isBlank, isPresent} from '../facade/lang';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
import {DetectChangesVars, ViewProperties} from './constants';
import {BoundTextAst, BoundElementPropertyAst, DirectiveAst, PropertyBindingType,} from '../template_ast';
import {CompileView} from './compile_view';
import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {camelCaseToDashCase} from '../util';
import {convertCdExpressionToIr} from './expression_converter';
import {CompileBinding} from './compile_binding';
import {BaseException, SecurityContext} from '@angular/core';
@ -287,12 +281,24 @@ export function bindDirectiveInputs(
function logBindingUpdateStmt(
renderNode: o.Expression, propName: string, value: o.Expression): o.Statement {
return o.THIS_EXPR.prop('renderer')
.callMethod(
'setBindingDebugInfo',
[
renderNode, o.literal(`ng-reflect-${camelCaseToDashCase(propName)}`),
value.isBlank().conditional(o.NULL_EXPR, value.callMethod('toString', []))
])
.toStmt();
const tryStmt =
o.THIS_EXPR.prop('renderer')
.callMethod(
'setBindingDebugInfo',
[
renderNode, o.literal(`ng-reflect-${camelCaseToDashCase(propName)}`),
value.isBlank().conditional(o.NULL_EXPR, value.callMethod('toString', []))
])
.toStmt();
const catchStmt = o.THIS_EXPR.prop('renderer')
.callMethod(
'setBindingDebugInfo',
[
renderNode, o.literal(`ng-reflect-${camelCaseToDashCase(propName)}`),
o.literal('[ERROR] Exception while trying to serialize the value')
])
.toStmt();
return new o.TryCatchStmt([tryStmt], [catchStmt]);
}

View File

@ -69,16 +69,13 @@ export abstract class Renderer {
abstract setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string):
void;
abstract setElementClass(renderElement: any, className: string, isAdd: boolean): any
/** TODO #9100 */;
abstract setElementClass(renderElement: any, className: string, isAdd: boolean): void;
abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): any
/** TODO #9100 */;
abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): void;
abstract invokeElementMethod(renderElement: any, methodName: string, args?: any[]): any
/** TODO #9100 */;
abstract invokeElementMethod(renderElement: any, methodName: string, args?: any[]): void;
abstract setText(renderNode: any, text: string): any /** TODO #9100 */;
abstract setText(renderNode: any, text: string): void;
abstract animate(
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],

View File

@ -1846,6 +1846,21 @@ function declareTests({useJit}: {useJit: boolean}) {
async.done();
});
}));
it('should indicate when toString() throws',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var tpl = '<div my-dir [elprop]="toStringThrow"></div>';
tcb.overrideView(MyComp, new ViewMetadata({template: tpl, directives: [MyDir]}))
.createAsync(MyComp)
.then((fixture) => {
fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.debugElement.nativeElement))
.toContain('[ERROR]');
async.done();
});
}));
});
describe('property decorators', () => {
@ -2227,6 +2242,8 @@ class MyComp {
ctxProp: string;
ctxNumProp: number;
ctxBoolProp: boolean;
toStringThrow = {toString: function() { throw 'boom'; }};
constructor() {
this.ctxProp = 'initial value';
this.ctxNumProp = 0;

View File

@ -1218,17 +1218,17 @@ export declare abstract class Renderer {
abstract createViewRoot(hostElement: any): any;
abstract destroyView(hostElement: any, viewAllNodes: any[]): void;
abstract detachView(viewRootNodes: any[]): void;
abstract invokeElementMethod(renderElement: any, methodName: string, args?: any[]): any;
abstract invokeElementMethod(renderElement: any, methodName: string, args?: any[]): void;
abstract listen(renderElement: any, name: string, callback: Function): Function;
abstract listenGlobal(target: string, name: string, callback: Function): Function;
abstract projectNodes(parentElement: any, nodes: any[]): void;
abstract selectRootElement(selectorOrNode: string | any, debugInfo?: RenderDebugInfo): any;
abstract setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string): void;
abstract setElementAttribute(renderElement: any, attributeName: string, attributeValue: string): void;
abstract setElementClass(renderElement: any, className: string, isAdd: boolean): any;
abstract setElementClass(renderElement: any, className: string, isAdd: boolean): void;
abstract setElementProperty(renderElement: any, propertyName: string, propertyValue: any): void;
abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): any;
abstract setText(renderNode: any, text: string): any;
abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): void;
abstract setText(renderNode: any, text: string): void;
}
/** @deprecated */