diff --git a/src/lib/tooltip/tooltip.spec.ts b/src/lib/tooltip/tooltip.spec.ts index 25bea8c35488..d3a5c1879d73 100644 --- a/src/lib/tooltip/tooltip.spec.ts +++ b/src/lib/tooltip/tooltip.spec.ts @@ -22,7 +22,12 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {Direction, Directionality} from '@angular/cdk/bidi'; import {OverlayContainer, OverlayModule, CdkScrollable} from '@angular/cdk/overlay'; import {Platform} from '@angular/cdk/platform'; -import {dispatchFakeEvent, dispatchKeyboardEvent, patchElementFocus} from '@angular/cdk/testing'; +import { + dispatchFakeEvent, + dispatchKeyboardEvent, + patchElementFocus, + dispatchMouseEvent, +} from '@angular/cdk/testing'; import {ESCAPE} from '@angular/cdk/keycodes'; import {FocusMonitor} from '@angular/cdk/a11y'; import { @@ -40,12 +45,12 @@ describe('MatTooltip', () => { let overlayContainer: OverlayContainer; let overlayContainerElement: HTMLElement; let dir: {value: Direction}; - let platform: {IOS: boolean, isBrowser: boolean}; + let platform: {IOS: boolean, isBrowser: boolean, ANDROID: boolean}; let focusMonitor: FocusMonitor; beforeEach(async(() => { // Set the default Platform override that can be updated before component creation. - platform = {IOS: false, isBrowser: true}; + platform = {IOS: false, isBrowser: true, ANDROID: false}; TestBed.configureTestingModule({ imports: [MatTooltipModule, OverlayModule, NoopAnimationsModule], @@ -808,6 +813,30 @@ describe('MatTooltip', () => { expect(fixture.componentInstance.button.nativeElement.style.webkitUserDrag).toBeFalsy(); }); + it('should not open on `mouseenter` on iOS', () => { + platform.IOS = true; + + const fixture = TestBed.createComponent(BasicTooltipDemo); + + fixture.detectChanges(); + dispatchMouseEvent(fixture.componentInstance.button.nativeElement, 'mouseenter'); + fixture.detectChanges(); + + assertTooltipInstance(fixture.componentInstance.tooltip, false); + }); + + it('should not open on `mouseenter` on Android', () => { + platform.ANDROID = true; + + const fixture = TestBed.createComponent(BasicTooltipDemo); + + fixture.detectChanges(); + dispatchMouseEvent(fixture.componentInstance.button.nativeElement, 'mouseenter'); + fixture.detectChanges(); + + assertTooltipInstance(fixture.componentInstance.tooltip, false); + }); + }); }); diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index c059be30d6f0..343b7f7700fc 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -185,7 +185,7 @@ export class MatTooltip implements OnDestroy { } } - private _manualListeners = new Map(); + private _manualListeners = new Map(); /** Emits when the component is destroyed. */ private readonly _destroyed = new Subject(); @@ -206,15 +206,14 @@ export class MatTooltip implements OnDestroy { const element: HTMLElement = _elementRef.nativeElement; - // The mouse events shouldn't be bound on iOS devices, because - // they can prevent the first tap from firing its click event. - if (!_platform.IOS) { - this._manualListeners.set('mouseenter', () => this.show()); - this._manualListeners.set('mouseleave', () => this.hide()); - + // The mouse events shouldn't be bound on mobile devices, because they can prevent the + // first tap from firing its click event or can cause the tooltip to open for clicks. + if (!_platform.IOS && !_platform.ANDROID) { this._manualListeners - .forEach((listener, event) => _elementRef.nativeElement.addEventListener(event, listener)); - } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + .set('mouseenter', () => this.show()) + .set('mouseleave', () => this.hide()) + .forEach((listener, event) => element.addEventListener(event, listener)); + } else if (_platform.IOS && (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA')) { // When we bind a gesture event on an element (in this case `longpress`), HammerJS // will add some inline styles by default, including `user-select: none`. This is // problematic on iOS, because it will prevent users from typing in inputs. If