From d6bc63fa38b6a55073118a8b5640252317419856 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Tue, 11 Feb 2020 19:56:46 +0100 Subject: [PATCH] fix(ivy): error if directive with synthetic property binding is on same node as directive that injects ViewContainerRef (#35343) In the `loadRenderer` we make an assumption that the value will always be an `LView`, but if there's a directive on the same node which injects `ViewContainerRef` the `LView` will be wrapped in an `LContainer`. These changes add a call to unwrap the value before we try to read the value off of it. Fixes #35342. PR Close #35343 --- .../core/src/render3/instructions/shared.ts | 4 +-- .../test/acceptance/property_binding_spec.ts | 31 ++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 58509c4517..ff00a5679c 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -36,7 +36,7 @@ import {NO_CHANGE} from '../tokens'; import {isAnimationProp, mergeHostAttrs} from '../util/attrs_utils'; import {INTERPOLATION_DELIMITER, renderStringify, stringifyForError} from '../util/misc_utils'; import {getLViewParent} from '../util/view_traversal_utils'; -import {getComponentLViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, viewAttachedToChangeDetector} from '../util/view_utils'; +import {getComponentLViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, unwrapLView, viewAttachedToChangeDetector} from '../util/view_utils'; import {selectIndexInternal} from './advance'; import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeDebug, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLViewFromTViewBlueprint, cloneToTViewData} from './lview_debug'; @@ -1934,7 +1934,7 @@ function getTViewCleanup(tView: TView): any[] { * instead of the current renderer (see the componentSyntheticHost* instructions). */ export function loadComponentRenderer(tNode: TNode, lView: LView): Renderer3 { - const componentLView = lView[tNode.index] as LView; + const componentLView = unwrapLView(lView[tNode.index]) !; return componentLView[RENDERER]; } diff --git a/packages/core/test/acceptance/property_binding_spec.ts b/packages/core/test/acceptance/property_binding_spec.ts index 802403e593..a2343c9009 100644 --- a/packages/core/test/acceptance/property_binding_spec.ts +++ b/packages/core/test/acceptance/property_binding_spec.ts @@ -5,8 +5,9 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {state, style, trigger} from '@angular/animations'; import {CommonModule} from '@angular/common'; -import {Component, Directive, EventEmitter, Input, Output} from '@angular/core'; +import {Component, Directive, EventEmitter, Input, Output, ViewContainerRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By, DomSanitizer, SafeUrl} from '@angular/platform-browser'; @@ -598,4 +599,32 @@ describe('property bindings', () => { }); + it('should not throw on synthetic property bindings when a directive on the same element injects ViewContainerRef', + () => { + @Component({ + selector: 'my-comp', + template: '', + animations: [trigger('trigger', [state('void', style({opacity: 0}))])], + host: {'[@trigger]': '"void"'} + }) + class MyComp { + } + + @Directive({selector: '[my-dir]'}) + class MyDir { + constructor(public viewContainerRef: ViewContainerRef) {} + } + + @Component({template: ''}) + class App { + } + + TestBed.configureTestingModule({declarations: [App, MyDir, MyComp]}); + + expect(() => { + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + }).not.toThrow(); + }); + });