From 552836ebf0de61797f00dc3c9206e09c74f9458b Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Thu, 8 Nov 2018 11:46:33 -0800 Subject: [PATCH] fix(ivy): merged host bindings functions should take superclass hostVars into account (#27013) PR Close #27013 --- .../features/inherit_definition_feature.ts | 1 + .../Inherit_definition_feature_spec.ts | 42 +++++++++++--- .../forms/test/template_integration_spec.ts | 55 +++++++++---------- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/packages/core/src/render3/features/inherit_definition_feature.ts b/packages/core/src/render3/features/inherit_definition_feature.ts index 77c124af1f..4a9de9835d 100644 --- a/packages/core/src/render3/features/inherit_definition_feature.ts +++ b/packages/core/src/render3/features/inherit_definition_feature.ts @@ -76,6 +76,7 @@ export function InheritDefinitionFeature(definition: DirectiveDef| Componen superHostBindings(directiveIndex, elementIndex); prevHostBindings(directiveIndex, elementIndex); }; + (definition as any).hostVars += superDef.hostVars; } else { definition.hostBindings = superHostBindings; } diff --git a/packages/core/test/render3/Inherit_definition_feature_spec.ts b/packages/core/test/render3/Inherit_definition_feature_spec.ts index 96c81ad2a1..2de9281c64 100644 --- a/packages/core/test/render3/Inherit_definition_feature_spec.ts +++ b/packages/core/test/render3/Inherit_definition_feature_spec.ts @@ -7,7 +7,8 @@ */ import {Inject, InjectionToken} from '../../src/core'; -import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, defineBase, defineComponent, defineDirective, directiveInject, element} from '../../src/render3/index'; +import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, bind, defineBase, defineComponent, defineDirective, directiveInject, element, elementProperty, load} from '../../src/render3/index'; + import {ComponentFixture, createComponent} from './render_util'; describe('InheritDefinitionFeature', () => { @@ -299,36 +300,61 @@ describe('InheritDefinitionFeature', () => { }); it('should compose hostBindings', () => { - const log: Array<[string, number, number]> = []; + let subDir !: SubDirective; class SuperDirective { + id = 'my-id'; + static ngDirectiveDef = defineDirective({ type: SuperDirective, selectors: [['', 'superDir', '']], hostBindings: (directiveIndex: number, elementIndex: number) => { - log.push(['super', directiveIndex, elementIndex]); + const instance = load(directiveIndex) as SuperDirective; + elementProperty(elementIndex, 'id', bind(instance.id)); }, + hostVars: 1, factory: () => new SuperDirective(), }); } class SubDirective extends SuperDirective { + title = 'my-title'; + static ngDirectiveDef = defineDirective({ type: SubDirective, selectors: [['', 'subDir', '']], hostBindings: (directiveIndex: number, elementIndex: number) => { - log.push(['sub', directiveIndex, elementIndex]); + const instance = load(directiveIndex) as SubDirective; + elementProperty(elementIndex, 'title', bind(instance.title)); }, - factory: () => new SubDirective(), + hostVars: 1, + factory: () => subDir = new SubDirective(), features: [InheritDefinitionFeature] }); } - const subDef = SubDirective.ngDirectiveDef as DirectiveDef; - subDef.hostBindings !(1, 2); + const App = createComponent('app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['subDir', '']); + } + }, 1, 0, [SubDirective]); - expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]); + const fixture = new ComponentFixture(App); + const divEl = fixture.hostElement.querySelector('div') as HTMLElement; + + expect(divEl.id).toEqual('my-id'); + expect(divEl.title).toEqual('my-title'); + + subDir.title = 'new-title'; + fixture.update(); + expect(divEl.id).toEqual('my-id'); + expect(divEl.title).toEqual('new-title'); + + subDir.id = 'new-id'; + fixture.update(); + expect(divEl.id).toEqual('new-id'); + expect(divEl.title).toEqual('new-title'); }); it('should compose viewQuery', () => { diff --git a/packages/forms/test/template_integration_spec.ts b/packages/forms/test/template_integration_spec.ts index 39db4df45b..db62d4cc15 100644 --- a/packages/forms/test/template_integration_spec.ts +++ b/packages/forms/test/template_integration_spec.ts @@ -1231,42 +1231,41 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat describe('validation directives', () => { - fixmeIvy('RequiredValidator provided instead of CheckboxRequiredValidator') && - it('required validator should validate checkbox', fakeAsync(() => { - const fixture = initTest(NgModelCheckboxRequiredValidator); - fixture.detectChanges(); - tick(); + it('required validator should validate checkbox', fakeAsync(() => { + const fixture = initTest(NgModelCheckboxRequiredValidator); + fixture.detectChanges(); + tick(); - const control = - fixture.debugElement.children[0].injector.get(NgForm).control.get('checkbox') !; + const control = + fixture.debugElement.children[0].injector.get(NgForm).control.get('checkbox') !; - const input = fixture.debugElement.query(By.css('input')); - expect(input.nativeElement.checked).toBe(false); - expect(control.hasError('required')).toBe(false); + const input = fixture.debugElement.query(By.css('input')); + expect(input.nativeElement.checked).toBe(false); + expect(control.hasError('required')).toBe(false); - fixture.componentInstance.required = true; - fixture.detectChanges(); - tick(); + fixture.componentInstance.required = true; + fixture.detectChanges(); + tick(); - expect(input.nativeElement.checked).toBe(false); - expect(control.hasError('required')).toBe(true); + expect(input.nativeElement.checked).toBe(false); + expect(control.hasError('required')).toBe(true); - input.nativeElement.checked = true; - dispatchEvent(input.nativeElement, 'change'); - fixture.detectChanges(); - tick(); + input.nativeElement.checked = true; + dispatchEvent(input.nativeElement, 'change'); + fixture.detectChanges(); + tick(); - expect(input.nativeElement.checked).toBe(true); - expect(control.hasError('required')).toBe(false); + expect(input.nativeElement.checked).toBe(true); + expect(control.hasError('required')).toBe(false); - input.nativeElement.checked = false; - dispatchEvent(input.nativeElement, 'change'); - fixture.detectChanges(); - tick(); + input.nativeElement.checked = false; + dispatchEvent(input.nativeElement, 'change'); + fixture.detectChanges(); + tick(); - expect(input.nativeElement.checked).toBe(false); - expect(control.hasError('required')).toBe(true); - })); + expect(input.nativeElement.checked).toBe(false); + expect(control.hasError('required')).toBe(true); + })); it('should validate email', fakeAsync(() => { const fixture = initTest(NgModelEmailValidator);