diff --git a/modules/@angular/compiler/src/output/output_ast.ts b/modules/@angular/compiler/src/output/output_ast.ts index b47c2f1e47..45a534caf3 100644 --- a/modules/@angular/compiler/src/output/output_ast.ts +++ b/modules/@angular/compiler/src/output/output_ast.ts @@ -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 = 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 = method; + this.name = method; this.builtin = null; } else { this.name = null; diff --git a/modules/@angular/compiler/src/view_compiler/property_binder.ts b/modules/@angular/compiler/src/view_compiler/property_binder.ts index 733cd96a98..7287a47031 100644 --- a/modules/@angular/compiler/src/view_compiler/property_binder.ts +++ b/modules/@angular/compiler/src/view_compiler/property_binder.ts @@ -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]); } diff --git a/modules/@angular/core/src/render/api.ts b/modules/@angular/core/src/render/api.ts index b26cd8e010..c3a7374a4e 100644 --- a/modules/@angular/core/src/render/api.ts +++ b/modules/@angular/core/src/render/api.ts @@ -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[], diff --git a/modules/@angular/core/test/linker/integration_spec.ts b/modules/@angular/core/test/linker/integration_spec.ts index 4a680fc35c..8762801275 100644 --- a/modules/@angular/core/test/linker/integration_spec.ts +++ b/modules/@angular/core/test/linker/integration_spec.ts @@ -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 = '
'; + 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; diff --git a/tools/public_api_guard/core/index.d.ts b/tools/public_api_guard/core/index.d.ts index 156dba1692..ceaca68adf 100644 --- a/tools/public_api_guard/core/index.d.ts +++ b/tools/public_api_guard/core/index.d.ts @@ -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 */