From c62c5e2999cb12933afd72fe95d5600ae1d33c44 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Wed, 15 May 2019 18:22:50 -0700 Subject: [PATCH] fix(ivy): do not throw if host style is on a template node (#30498) In View Engine, we would simply ignore host style bindings on template nodes. In Ivy, we are throwing a "Cannot read length of undefined" error instead. For backwards compatibility, we should also ignore these bindings rather than blowing up. PR Close #30498 --- .../styling/host_instructions_queue.ts | 9 ++++++--- packages/core/test/acceptance/styling_spec.ts | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/core/src/render3/styling/host_instructions_queue.ts b/packages/core/src/render3/styling/host_instructions_queue.ts index a691397fb4..e5045cd9e7 100644 --- a/packages/core/src/render3/styling/host_instructions_queue.ts +++ b/packages/core/src/render3/styling/host_instructions_queue.ts @@ -35,9 +35,12 @@ export function registerHostDirective(context: StylingContext, directiveIndex: n */ export function enqueueHostInstruction( context: StylingContext, priority: number, instructionFn: T, instructionFnArgs: ParamsOf) { - const buffer: HostInstructionsQueue = context[StylingIndex.HostInstructionsQueue] !; - const index = findNextInsertionIndex(buffer, priority); - buffer.splice(index, 0, priority, instructionFn, instructionFnArgs); + const buffer: HostInstructionsQueue|null = context[StylingIndex.HostInstructionsQueue]; + // Buffer may be null if host element is a template node. In this case, just ignore the style. + if (buffer != null) { + const index = findNextInsertionIndex(buffer, priority); + buffer.splice(index, 0, priority, instructionFn, instructionFnArgs); + } } /** diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts index fa5e7237b6..66a53b619d 100644 --- a/packages/core/test/acceptance/styling_spec.ts +++ b/packages/core/test/acceptance/styling_spec.ts @@ -160,4 +160,24 @@ describe('styling', () => { tNode: 3, }); }); + + it('should not throw if host style binding is on a template node', () => { + // This ex is a bit contrived. In real apps, you might have a shared class that is extended both + // by components with host elements and by directives on template nodes. In that case, the host + // styles for the template directives should just be ignored. + @Directive({selector: 'ng-template[styleDir]', host: {'[style.display]': 'display'}}) + class StyleDir { + display = 'block'; + } + + @Component({selector: 'app-comp', template: ``}) + class MyApp { + } + + TestBed.configureTestingModule({declarations: [MyApp, StyleDir]}); + expect(() => { + const fixture = TestBed.createComponent(MyApp); + fixture.detectChanges(); + }).not.toThrow(); + }); });