Skip to content

Commit 744ff15

Browse files
committed
fix(tooltip): avoid capturing the initial tap on mobile
Currently the tooltip always binds the `mouseenter` and `mouseleave` events, however this can cause the click handlers on the tooltip host not to be fired on the first tap. These changes switch to binding the events only on devices that have touch events. Fixes #2326.
1 parent 026c70a commit 744ff15

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/lib/core/platform/features.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ export function getSupportedInputTypes(): Set<string> {
3434
}
3535
return supportedInputTypes;
3636
}
37+
38+
/** Whether the current browser supports touch events. */
39+
export const HAS_TOUCH_EVENTS = typeof window !== 'undefined' && !!(('ontouchstart' in window) ||
40+
((window as any).DocumentTouch && document instanceof (window as any).DocumentTouch));

src/lib/tooltip/tooltip.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
AnimationTransitionEvent,
1515
NgZone,
1616
Optional,
17-
OnDestroy
17+
OnDestroy,
18+
Renderer,
1819
} from '@angular/core';
1920
import {
2021
Overlay,
@@ -31,6 +32,7 @@ import {Observable} from 'rxjs/Observable';
3132
import {Subject} from 'rxjs/Subject';
3233
import {Dir} from '../core/rtl/dir';
3334
import {OVERLAY_PROVIDERS} from '../core/overlay/overlay';
35+
import {HAS_TOUCH_EVENTS} from '../core/platform/features';
3436
import 'rxjs/add/operator/first';
3537

3638
export type TooltipPosition = 'left' | 'right' | 'above' | 'below' | 'before' | 'after';
@@ -49,8 +51,6 @@ export const TOUCHEND_HIDE_DELAY = 1500;
4951
host: {
5052
'(longpress)': 'show()',
5153
'(touchend)': 'hide(' + TOUCHEND_HIDE_DELAY + ')',
52-
'(mouseenter)': 'show()',
53-
'(mouseleave)': 'hide()',
5454
},
5555
exportAs: 'mdTooltip',
5656
})
@@ -102,11 +102,21 @@ export class MdTooltip implements OnDestroy {
102102
get _deprecatedMessage(): string { return this.message; }
103103
set _deprecatedMessage(v: string) { this.message = v; }
104104

105-
constructor(private _overlay: Overlay,
106-
private _elementRef: ElementRef,
107-
private _viewContainerRef: ViewContainerRef,
108-
private _ngZone: NgZone,
109-
@Optional() private _dir: Dir) { }
105+
constructor(
106+
private _overlay: Overlay,
107+
private _elementRef: ElementRef,
108+
private _viewContainerRef: ViewContainerRef,
109+
private _ngZone: NgZone,
110+
private _renderer: Renderer,
111+
@Optional() private _dir: Dir) {
112+
113+
// The mouse events shouldn't be bound on touch devices, because
114+
// they can prevent the first tap from firing it's click event.
115+
if (!HAS_TOUCH_EVENTS) {
116+
_renderer.listen(_elementRef.nativeElement, 'mouseenter', () => this.show());
117+
_renderer.listen(_elementRef.nativeElement, 'mouseleave', () => this.hide());
118+
}
119+
}
110120

111121
/**
112122
* Dispose the tooltip when destroyed.

0 commit comments

Comments
 (0)