Skip to content

Commit e0de1ed

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 aa22368 commit e0de1ed

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
// action desired when such a click occurs (usually closing the overlay).
394403
this._backdropElement.addEventListener('click', this._backdropClickHandler);
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
@@ -769,6 +769,40 @@ describe('Overlay', () => {
769769
expect(backdropClickHandler).toHaveBeenCalledTimes(1);
770770
});
771771

772+
it('should disable pointer events on the backdrop when scrolling', fakeAsync(() => {
773+
let overlayRef = overlay.create(config);
774+
overlayRef.attach(componentPortal);
775+
776+
viewContainerFixture.detectChanges();
777+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
778+
779+
expect(backdrop.style.pointerEvents).toBeFalsy();
780+
781+
dispatchFakeEvent(backdrop, 'wheel');
782+
783+
expect(backdrop.style.pointerEvents).toBe('none');
784+
785+
tick(100);
786+
787+
expect(backdrop.style.pointerEvents).toBeFalsy();
788+
}));
789+
790+
it('should not disable pointer events on the backdrop when scrolling is blocked', () => {
791+
config.scrollStrategy = overlay.scrollStrategies.block();
792+
793+
let overlayRef = overlay.create(config);
794+
overlayRef.attach(componentPortal);
795+
796+
viewContainerFixture.detectChanges();
797+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
798+
799+
expect(backdrop.style.pointerEvents).toBeFalsy();
800+
801+
dispatchFakeEvent(backdrop, 'wheel');
802+
803+
expect(backdrop.style.pointerEvents).toBeFalsy();
804+
});
805+
772806
});
773807

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

0 commit comments

Comments
 (0)