Skip to content

Commit 8089a54

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 b49bfce commit 8089a54

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/lib/core/platform/features.ts

+4
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

+18-8
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,
@@ -30,6 +31,7 @@ import {MdTooltipInvalidPositionError} from './tooltip-errors';
3031
import {Observable} from 'rxjs/Observable';
3132
import {Subject} from 'rxjs/Subject';
3233
import {Dir} from '../core/rtl/dir';
34+
import {HAS_TOUCH_EVENTS} from '../core/platform/features';
3335
import 'rxjs/add/operator/first';
3436

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

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

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

0 commit comments

Comments
 (0)