Skip to content

Commit a6b8a06

Browse files
crisbetojelbourn
authored andcommitted
fix(tooltip): opening after click on android (#12250)
Fixes the tooltip opening on clicks on Android devices. Also does some minor cleanup. Fixes #12223.
1 parent d08d8bc commit a6b8a06

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

src/lib/tooltip/tooltip.spec.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
2222
import {Direction, Directionality} from '@angular/cdk/bidi';
2323
import {OverlayContainer, OverlayModule, CdkScrollable} from '@angular/cdk/overlay';
2424
import {Platform} from '@angular/cdk/platform';
25-
import {dispatchFakeEvent, dispatchKeyboardEvent, patchElementFocus} from '@angular/cdk/testing';
25+
import {
26+
dispatchFakeEvent,
27+
dispatchKeyboardEvent,
28+
patchElementFocus,
29+
dispatchMouseEvent,
30+
} from '@angular/cdk/testing';
2631
import {ESCAPE} from '@angular/cdk/keycodes';
2732
import {FocusMonitor} from '@angular/cdk/a11y';
2833
import {
@@ -40,12 +45,12 @@ describe('MatTooltip', () => {
4045
let overlayContainer: OverlayContainer;
4146
let overlayContainerElement: HTMLElement;
4247
let dir: {value: Direction};
43-
let platform: {IOS: boolean, isBrowser: boolean};
48+
let platform: {IOS: boolean, isBrowser: boolean, ANDROID: boolean};
4449
let focusMonitor: FocusMonitor;
4550

4651
beforeEach(async(() => {
4752
// Set the default Platform override that can be updated before component creation.
48-
platform = {IOS: false, isBrowser: true};
53+
platform = {IOS: false, isBrowser: true, ANDROID: false};
4954

5055
TestBed.configureTestingModule({
5156
imports: [MatTooltipModule, OverlayModule, NoopAnimationsModule],
@@ -808,6 +813,30 @@ describe('MatTooltip', () => {
808813
expect(fixture.componentInstance.button.nativeElement.style.webkitUserDrag).toBeFalsy();
809814
});
810815

816+
it('should not open on `mouseenter` on iOS', () => {
817+
platform.IOS = true;
818+
819+
const fixture = TestBed.createComponent(BasicTooltipDemo);
820+
821+
fixture.detectChanges();
822+
dispatchMouseEvent(fixture.componentInstance.button.nativeElement, 'mouseenter');
823+
fixture.detectChanges();
824+
825+
assertTooltipInstance(fixture.componentInstance.tooltip, false);
826+
});
827+
828+
it('should not open on `mouseenter` on Android', () => {
829+
platform.ANDROID = true;
830+
831+
const fixture = TestBed.createComponent(BasicTooltipDemo);
832+
833+
fixture.detectChanges();
834+
dispatchMouseEvent(fixture.componentInstance.button.nativeElement, 'mouseenter');
835+
fixture.detectChanges();
836+
837+
assertTooltipInstance(fixture.componentInstance.tooltip, false);
838+
});
839+
811840
});
812841

813842
});

src/lib/tooltip/tooltip.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export class MatTooltip implements OnDestroy {
185185
}
186186
}
187187

188-
private _manualListeners = new Map<string, Function>();
188+
private _manualListeners = new Map<string, EventListenerOrEventListenerObject>();
189189

190190
/** Emits when the component is destroyed. */
191191
private readonly _destroyed = new Subject<void>();
@@ -206,15 +206,14 @@ export class MatTooltip implements OnDestroy {
206206

207207
const element: HTMLElement = _elementRef.nativeElement;
208208

209-
// The mouse events shouldn't be bound on iOS devices, because
210-
// they can prevent the first tap from firing its click event.
211-
if (!_platform.IOS) {
212-
this._manualListeners.set('mouseenter', () => this.show());
213-
this._manualListeners.set('mouseleave', () => this.hide());
214-
209+
// The mouse events shouldn't be bound on mobile devices, because they can prevent the
210+
// first tap from firing its click event or can cause the tooltip to open for clicks.
211+
if (!_platform.IOS && !_platform.ANDROID) {
215212
this._manualListeners
216-
.forEach((listener, event) => _elementRef.nativeElement.addEventListener(event, listener));
217-
} else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
213+
.set('mouseenter', () => this.show())
214+
.set('mouseleave', () => this.hide())
215+
.forEach((listener, event) => element.addEventListener(event, listener));
216+
} else if (_platform.IOS && (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA')) {
218217
// When we bind a gesture event on an element (in this case `longpress`), HammerJS
219218
// will add some inline styles by default, including `user-select: none`. This is
220219
// problematic on iOS, because it will prevent users from typing in inputs. If

0 commit comments

Comments
 (0)