From 5d824c4153d6d9fcad7975cb226ac3d1e5ac8693 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Mon, 15 Apr 2019 21:59:51 +0200 Subject: [PATCH] fix(ivy): DebugNode.properties not preserving type of values (#29914) Fixes the `DebugNode.properties` casting all of the values to a string. This PR resolves FW-1253. PR Close #29914 --- packages/core/src/debug/debug_node.ts | 13 +++++++----- packages/core/test/debug/debug_node_spec.ts | 23 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 722009eb21..7e2a3210ee 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -538,23 +538,26 @@ function collectPropertyBindings( let bindingIndex = getFirstBindingIndex(tNode.propertyMetadataStartIndex, tData); while (bindingIndex < tNode.propertyMetadataEndIndex) { - let value = ''; + let value: any; let propMetadata = tData[bindingIndex] as string; while (!isPropMetadataString(propMetadata)) { // This is the first value for an interpolation. We need to build up // the full interpolation by combining runtime values in LView with // the static interstitial values stored in TData. - value += renderStringify(lView[bindingIndex]) + tData[bindingIndex]; + value = (value || '') + renderStringify(lView[bindingIndex]) + tData[bindingIndex]; propMetadata = tData[++bindingIndex] as string; } - value += lView[bindingIndex]; + value = value === undefined ? lView[bindingIndex] : value += lView[bindingIndex]; // Property metadata string has 3 parts: property name, prefix, and suffix const metadataParts = propMetadata.split(INTERPOLATION_DELIMITER); const propertyName = metadataParts[0]; // Attr bindings don't have property names and should be skipped if (propertyName) { - // Wrap value with prefix and suffix (will be '' for normal bindings) - properties[propertyName] = metadataParts[1] + value + metadataParts[2]; + // Wrap value with prefix and suffix (will be '' for normal bindings), if they're defined. + // Avoid wrapping for normal bindings so that the value doesn't get cast to a string. + properties[propertyName] = (metadataParts[1] && metadataParts[2]) ? + metadataParts[1] + value + metadataParts[2] : + value; } bindingIndex++; } diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index 22acf260ba..150c20c60a 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -195,6 +195,20 @@ class TestCmptWithViewContainerRef { constructor(private vcref: ViewContainerRef) {} } +@Component({ + template: ` + +` +}) +class TestCmptWithPropBindings { + disabled = true; + tabIndex = 1337; + title = 'hello'; +} + { describe('debug element', () => { let fixture: ComponentFixture; @@ -218,6 +232,7 @@ class TestCmptWithViewContainerRef { HostClassBindingCmp, TestCmptWithViewContainerRef, SimpleContentComp, + TestCmptWithPropBindings, ], providers: [Logger], schemas: [NO_ERRORS_SCHEMA], @@ -566,6 +581,14 @@ class TestCmptWithViewContainerRef { expect(debugElement.properties.className).toBeFalsy(); }); + it('should preserve the type of the property values', () => { + const fixture = TestBed.createComponent(TestCmptWithPropBindings); + fixture.detectChanges(); + + const button = fixture.debugElement.query(By.css('button')); + expect(button.properties).toEqual({disabled: true, tabIndex: 1337, title: 'hello'}); + }); + describe('componentInstance on DebugNode', () => { it('should return component associated with a node if a node is a component host', () => {