Skip to content

Commit 06d2d4a

Browse files
committed
fix(overlay): backdrop blocking element scroll
Fixes a long-standing where the backdrop doesn't allow the user to scroll, if the main scrollable container is not the body. Fixes #6927.
1 parent 1e1751f commit 06d2d4a

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

src/cdk/overlay/overlay-ref.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
import {Direction, Directionality} from '@angular/cdk/bidi';
1010
import {ComponentPortal, Portal, PortalOutlet, TemplatePortal} from '@angular/cdk/portal';
1111
import {ComponentRef, EmbeddedViewRef, NgZone} from '@angular/core';
12-
import {Observable, Subject, merge} from 'rxjs';
13-
import {take, takeUntil} from 'rxjs/operators';
12+
import {Observable, Subject, merge, fromEvent} from 'rxjs';
13+
import {take, takeUntil, tap, debounceTime} from 'rxjs/operators';
1414
import {OverlayKeyboardDispatcher} from './keyboard/overlay-keyboard-dispatcher';
1515
import {OverlayConfig} from './overlay-config';
1616
import {coerceCssPixelValue, coerceArray} from '@angular/cdk/coercion';
1717
import {OverlayReference} from './overlay-reference';
18+
import {BlockScrollStrategy} from './scroll/index';
1819

1920

2021
/** An object where all of its properties cannot be written. */
@@ -346,6 +347,19 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
346347
this._backdropElement.addEventListener('click',
347348
(event: MouseEvent) => this._backdropClick.next(event));
348349

350+
if (!(this._config.scrollStrategy instanceof BlockScrollStrategy)) {
351+
// When the user starts scrolling by mouse, disable pointer events on the backdrop. This
352+
// allows for non-body scroll containers (e.g. a sidenav container), which would normally
353+
// be blocked due to the backdrop, to scroll. When the user has stopped scrolling for 100ms
354+
// restore the pointer events in order for the click handler to work.
355+
this._ngZone.runOutsideAngular(() => {
356+
fromEvent(this._backdropElement!, 'wheel').pipe(
357+
tap(() => this._backdropElement!.style.pointerEvents = 'none'),
358+
debounceTime(100)
359+
).subscribe(() => this._backdropElement!.style.pointerEvents = '');
360+
});
361+
}
362+
349363
// Add class to fade-in the backdrop after one frame.
350364
if (typeof requestAnimationFrame !== 'undefined') {
351365
this._ngZone.runOutsideAngular(() => {

src/cdk/overlay/overlay.spec.ts

+35
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
PositionStrategy,
2727
ScrollStrategy,
2828
} from './index';
29+
import {dispatchFakeEvent} from '@angular/cdk/testing';
2930

3031

3132
describe('Overlay', () => {
@@ -640,6 +641,40 @@ describe('Overlay', () => {
640641
.toBeLessThan(children.indexOf(host), 'Expected backdrop to be before the host in the DOM');
641642
});
642643

644+
it('should disable pointer events on the backdrop when scrolling', fakeAsync(() => {
645+
let overlayRef = overlay.create(config);
646+
overlayRef.attach(componentPortal);
647+
648+
viewContainerFixture.detectChanges();
649+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
650+
651+
expect(backdrop.style.pointerEvents).toBeFalsy();
652+
653+
dispatchFakeEvent(backdrop, 'wheel');
654+
655+
expect(backdrop.style.pointerEvents).toBe('none');
656+
657+
tick(100);
658+
659+
expect(backdrop.style.pointerEvents).toBeFalsy();
660+
}));
661+
662+
it('should not disable pointer events on the backdrop when scrolling is blocked', () => {
663+
config.scrollStrategy = overlay.scrollStrategies.block();
664+
665+
let overlayRef = overlay.create(config);
666+
overlayRef.attach(componentPortal);
667+
668+
viewContainerFixture.detectChanges();
669+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
670+
671+
expect(backdrop.style.pointerEvents).toBeFalsy();
672+
673+
dispatchFakeEvent(backdrop, 'wheel');
674+
675+
expect(backdrop.style.pointerEvents).toBeFalsy();
676+
});
677+
643678
});
644679

645680
describe('panelClass', () => {

0 commit comments

Comments
 (0)