Skip to content

Commit 2e2d811

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 ae41a0a commit 2e2d811

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

src/cdk/overlay/overlay-ref.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@ 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';
1212
import {Location} from '@angular/common';
13-
import {Observable, Subject, merge, SubscriptionLike, Subscription, Observer} from 'rxjs';
14-
import {take, takeUntil} from 'rxjs/operators';
13+
import {
14+
Observable,
15+
Subject,
16+
merge,
17+
SubscriptionLike,
18+
Subscription,
19+
Observer,
20+
fromEvent,
21+
} from 'rxjs';
22+
import {take, takeUntil, tap, debounceTime} from 'rxjs/operators';
1523
import {OverlayKeyboardDispatcher} from './keyboard/overlay-keyboard-dispatcher';
1624
import {OverlayConfig} from './overlay-config';
1725
import {coerceCssPixelValue, coerceArray} from '@angular/cdk/coercion';
1826
import {OverlayReference} from './overlay-reference';
1927
import {PositionStrategy} from './position/position-strategy';
2028
import {ScrollStrategy} from './scroll';
29+
import {BlockScrollStrategy} from './scroll/block-scroll-strategy';
2130

2231

2332
/** An object where all of its properties cannot be written. */
@@ -393,6 +402,19 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
393402
this._backdropElement.addEventListener('click',
394403
(event: MouseEvent) => this._backdropClick.next(event));
395404

405+
if (!(this._config.scrollStrategy instanceof BlockScrollStrategy)) {
406+
// When the user starts scrolling by mouse, disable pointer events on the backdrop. This
407+
// allows for non-body scroll containers (e.g. a sidenav container), which would normally
408+
// be blocked due to the backdrop, to scroll. When the user has stopped scrolling for 100ms
409+
// restore the pointer events in order for the click handler to work.
410+
this._ngZone.runOutsideAngular(() => {
411+
fromEvent(this._backdropElement!, 'wheel').pipe(
412+
tap(() => this._backdropElement!.style.pointerEvents = 'none'),
413+
debounceTime(100)
414+
).subscribe(() => this._backdropElement!.style.pointerEvents = '');
415+
});
416+
}
417+
396418
// Add class to fade-in the backdrop after one frame.
397419
if (typeof requestAnimationFrame !== 'undefined') {
398420
this._ngZone.runOutsideAngular(() => {

src/cdk/overlay/overlay.spec.ts

+34
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,40 @@ describe('Overlay', () => {
745745
.toBeLessThan(children.indexOf(host), 'Expected backdrop to be before the host in the DOM');
746746
});
747747

748+
it('should disable pointer events on the backdrop when scrolling', fakeAsync(() => {
749+
let overlayRef = overlay.create(config);
750+
overlayRef.attach(componentPortal);
751+
752+
viewContainerFixture.detectChanges();
753+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
754+
755+
expect(backdrop.style.pointerEvents).toBeFalsy();
756+
757+
dispatchFakeEvent(backdrop, 'wheel');
758+
759+
expect(backdrop.style.pointerEvents).toBe('none');
760+
761+
tick(100);
762+
763+
expect(backdrop.style.pointerEvents).toBeFalsy();
764+
}));
765+
766+
it('should not disable pointer events on the backdrop when scrolling is blocked', () => {
767+
config.scrollStrategy = overlay.scrollStrategies.block();
768+
769+
let overlayRef = overlay.create(config);
770+
overlayRef.attach(componentPortal);
771+
772+
viewContainerFixture.detectChanges();
773+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
774+
775+
expect(backdrop.style.pointerEvents).toBeFalsy();
776+
777+
dispatchFakeEvent(backdrop, 'wheel');
778+
779+
expect(backdrop.style.pointerEvents).toBeFalsy();
780+
});
781+
748782
});
749783

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

0 commit comments

Comments
 (0)