Skip to content

Commit

Permalink
fix: listen to touchstart events for outside click.
Browse files Browse the repository at this point in the history
This allows us to dismiss dropdown panel when touching elements outside
the selection menu on touch-enabled devices such as phones.

Use `fromEvent` instead of `fromEventPattern` so the event handlers
are (automatically) unregistered when the stream is unsubscribed. See
https://rxjs-dev.firebaseapp.com/api/index/function/fromEvent#description.
  • Loading branch information
zonr committed Aug 10, 2018
1 parent d8c7749 commit 70fcd66
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
20 changes: 14 additions & 6 deletions src/ng-select/ng-dropdown-panel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ import {
AfterContentInit,
OnInit,
OnChanges,
HostListener
HostListener,
Optional
} from '@angular/core';
import { DOCUMENT } from '@angular/common';

import { NgOption } from './ng-select.types';
import { NgSelectComponent, DropdownPosition } from './ng-select.component';
import { ItemsList } from './items-list';
import { WindowService } from './window.service';
import { VirtualScrollService } from './virtual-scroll.service';
import { takeUntil } from 'rxjs/operators';
import { Subject, fromEventPattern } from 'rxjs';
import { Subject, fromEvent, merge } from 'rxjs';

const TOP_CSS_CLASS = 'ng-select-top';
const BOTTOM_CSS_CLASS = 'ng-select-bottom';
Expand Down Expand Up @@ -87,7 +89,8 @@ export class NgDropdownPanelComponent implements OnInit, OnChanges, OnDestroy, A
private _elementRef: ElementRef,
private _zone: NgZone,
private _virtualScrollService: VirtualScrollService,
private _window: WindowService
private _window: WindowService,
@Optional() @Inject(DOCUMENT) private _document: any
) {
this._selectElement = _ngSelect.elementRef.nativeElement;
this._itemsList = _ngSelect.itemsList;
Expand All @@ -105,9 +108,14 @@ export class NgDropdownPanelComponent implements OnInit, OnChanges, OnDestroy, A

ngOnInit() {
this._handleScroll();
fromEventPattern((handler: any) => document.addEventListener('mousedown', handler, true))
.pipe(takeUntil(this._destroy$))
.subscribe(($event) => this._handleOutsideClick($event))
if (this._document) {
merge(
fromEvent(this._document, 'touchstart', { capture: true }),
fromEvent(this._document, 'mousedown', { capture: true })
)
.pipe(takeUntil(this._destroy$))
.subscribe(($event) => this._handleOutsideClick($event));
}
}

ngOnChanges(changes: SimpleChanges) {
Expand Down
9 changes: 9 additions & 0 deletions src/ng-select/ng-select.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,15 @@ describe('NgSelectComponent', function () {
expect(fixture.componentInstance.select.isOpen).toBeFalsy();
}));

it('should close dropdown if opened and touched outside dropdown container', fakeAsync(() => {
triggerKeyDownEvent(getNgSelectElement(fixture), KeyCode.Space);
expect(fixture.componentInstance.select.isOpen).toBeTruthy();
let event = new TouchEvent('touchstart', { bubbles: true });
document.getElementById('outside').dispatchEvent(event);
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select.isOpen).toBeFalsy();
}));

it('should prevent dropdown close if clicked on select', fakeAsync(() => {
triggerKeyDownEvent(getNgSelectElement(fixture), KeyCode.Space);
expect(select.isOpen).toBeTruthy();
Expand Down

0 comments on commit 70fcd66

Please sign in to comment.