diff --git a/src/modules/dropdown/dropdown-adapter.service.ts b/src/modules/dropdown/dropdown-adapter.service.ts index 495c82ac5..3d434b22b 100644 --- a/src/modules/dropdown/dropdown-adapter.service.ts +++ b/src/modules/dropdown/dropdown-adapter.service.ts @@ -11,7 +11,7 @@ const CLS_NO_SCROLL = 'sky-dropdown-no-scroll'; @Injectable() export class SkyDropdownAdapterService { public dropdownClose = new EventEmitter(); - private scrollListener: Function; + private scrollListeners: Array = []; constructor() { } @@ -32,7 +32,7 @@ export class SkyDropdownAdapterService { // Do not need to disable scroll when in full screen dropdown mode if (!isFullScreen) { - this.scrollListener = this.setupParentScrollHandler(dropdownEl, windowObj, renderer); + this.scrollListeners = this.setupParentScrollHandler(dropdownEl, windowObj, renderer); } } @@ -46,8 +46,12 @@ export class SkyDropdownAdapterService { this.setDropdownDefaults(menuEl, renderer, windowObj, false); this.dropdownClose.emit(undefined); - if (this.scrollListener) { - this.scrollListener(); + if (this.scrollListeners.length > 0) { + for (let i = 0; i < this.scrollListeners.length; i++) { + this.scrollListeners[i](); + } + + this.scrollListeners = []; } } } @@ -97,13 +101,15 @@ export class SkyDropdownAdapterService { private setupParentScrollHandler( dropdownEl: ElementRef, windowObj: Window, - renderer: Renderer): Function { + renderer: Renderer): Array { - let parentEl = this.getScrollableParentEl(dropdownEl, windowObj); + let parentEls = this.getAllScrollableParentEl(dropdownEl, windowObj); + let listeners: Array = []; /* istanbul ignore else */ /* sanity check */ - if (parentEl) { - let listener: any; + for (let i = 0; i < parentEls.length; i++) { + let listener: Function; + let parentEl = parentEls[i]; if (parentEl === document.body) { listener = renderer.listenGlobal('window', 'scroll', () => { this.dropdownClose.emit(undefined); @@ -117,8 +123,10 @@ export class SkyDropdownAdapterService { }); } - return listener; + listeners.push(listener); + } + return listeners; } private setDropdownDefaults( @@ -246,14 +254,15 @@ export class SkyDropdownAdapterService { }; } - private getScrollableParentEl(el: ElementRef, windowObj: Window): HTMLElement { + private getAllScrollableParentEl(el: ElementRef, windowObj: Window): Array { let overflowY: string, + result: Array = [document.body], parentEl = el.nativeElement.parentNode; - while (parentEl !== undefined && parentEl instanceof HTMLElement) { - if (parentEl === document.body) { - return parentEl; - } + while ( + parentEl !== undefined && + parentEl instanceof HTMLElement && + parentEl !== document.body) { overflowY = windowObj.getComputedStyle(parentEl, undefined).overflowY; @@ -264,7 +273,8 @@ export class SkyDropdownAdapterService { case 'AUTO': case 'HIDDEN': case 'SCROLL': - return parentEl; + result.push(parentEl); + break; default: break; } @@ -272,6 +282,7 @@ export class SkyDropdownAdapterService { parentEl = parentEl.parentNode; } + return result; } private getMenuEl(dropdownEl: ElementRef): HTMLElement { diff --git a/src/modules/dropdown/dropdown.component.spec.ts b/src/modules/dropdown/dropdown.component.spec.ts index 71b3b583d..8299f720c 100644 --- a/src/modules/dropdown/dropdown.component.spec.ts +++ b/src/modules/dropdown/dropdown.component.spec.ts @@ -82,6 +82,28 @@ describe('Dropdown component', () => { expect(dropdownMenu3).not.toBeVisible(); }); + + it('should close dropdown on multiple parent scroll', () => { + + let fixture = TestBed.createComponent(DropdownParentTestComponent); + let el: HTMLElement = fixture.nativeElement; + + fixture.detectChanges(); + + let dropdown1BtnEl = el.querySelector('#dropdown-1 .sky-dropdown-button') as HTMLElement; + + dropdown1BtnEl.click(); + fixture.detectChanges(); + + let windowScrollEvt = document.createEvent('CustomEvent'); + windowScrollEvt.initEvent('scroll', false, false); + + window.dispatchEvent(windowScrollEvt); + + let dropdownMenu1 = el.querySelector('#dropdown-1 .sky-dropdown-menu') as HTMLElement; + + expect(dropdownMenu1).not.toBeVisible(); + }); }); describe('postition tests', () => {