Skip to content

Commit ddc2e23

Browse files
feat(cdk/scrolling): update ScrollDispatcher to allow HTMLElement parameters (#21201)
Update ScrollDispatcher API to take elements of either ElementRef or HTMLElement. This is to maintain consistency with newer APIs. Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 7a8762a commit ddc2e23

File tree

4 files changed

+60
-9
lines changed

4 files changed

+60
-9
lines changed

src/cdk/scrolling/scroll-dispatcher.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ describe('ScrollDispatcher', () => {
159159
expect(scrollableElementIds).toEqual(['scrollable-1', 'scrollable-1a']);
160160
});
161161

162+
it('allows a raw HTMLElement', () => {
163+
const scrollContainers = scroll.getAncestorScrollContainers(element.nativeElement);
164+
const scrollableElementIds =
165+
scrollContainers.map(scrollable => scrollable.getElementRef().nativeElement.id);
166+
167+
expect(scrollableElementIds).toEqual(['scrollable-1', 'scrollable-1a']);
168+
});
169+
162170
it('should emit when one of the ancestor scrollable containers is scrolled', () => {
163171
const spy = jasmine.createSpy('scroll spy');
164172
const subscription = scroll.ancestorScrolled(element, 0).subscribe(spy);
@@ -173,6 +181,22 @@ describe('ScrollDispatcher', () => {
173181
subscription.unsubscribe();
174182
});
175183

184+
it('should emit when one of the ancestor scrollable containers is scrolled (HTMLElement API)',
185+
() => {
186+
const spy = jasmine.createSpy('scroll spy');
187+
const subscription = scroll.ancestorScrolled(element.nativeElement, 0).subscribe(spy);
188+
const grandparent = fixture.debugElement.nativeElement.querySelector('#scrollable-1');
189+
190+
dispatchFakeEvent(grandparent, 'scroll', false);
191+
expect(spy).toHaveBeenCalledTimes(1);
192+
193+
dispatchFakeEvent(window.document, 'scroll', false);
194+
expect(spy).toHaveBeenCalledTimes(2);
195+
196+
subscription.unsubscribe();
197+
});
198+
199+
176200
it('should not emit when a non-ancestor is scrolled', () => {
177201
const spy = jasmine.createSpy('scroll spy');
178202
const subscription = scroll.ancestorScrolled(element, 0).subscribe(spy);

src/cdk/scrolling/scroll-dispatcher.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {coerceElement} from '@angular/cdk/coercion';
910
import {Platform} from '@angular/cdk/platform';
1011
import {ElementRef, Injectable, NgZone, OnDestroy, Optional, Inject} from '@angular/core';
1112
import {fromEvent, of as observableOf, Subject, Subscription, Observable, Observer} from 'rxjs';
@@ -119,23 +120,25 @@ export class ScrollDispatcher implements OnDestroy {
119120
/**
120121
* Returns an observable that emits whenever any of the
121122
* scrollable ancestors of an element are scrolled.
122-
* @param elementRef Element whose ancestors to listen for.
123+
* @param elementOrElementRef Element whose ancestors to listen for.
123124
* @param auditTimeInMs Time to throttle the scroll events.
124125
*/
125-
ancestorScrolled(elementRef: ElementRef, auditTimeInMs?: number): Observable<CdkScrollable|void> {
126-
const ancestors = this.getAncestorScrollContainers(elementRef);
126+
ancestorScrolled(
127+
elementOrElementRef: ElementRef|HTMLElement,
128+
auditTimeInMs?: number): Observable<CdkScrollable|void> {
129+
const ancestors = this.getAncestorScrollContainers(elementOrElementRef);
127130

128131
return this.scrolled(auditTimeInMs).pipe(filter(target => {
129132
return !target || ancestors.indexOf(target) > -1;
130133
}));
131134
}
132135

133136
/** Returns all registered Scrollables that contain the provided element. */
134-
getAncestorScrollContainers(elementRef: ElementRef): CdkScrollable[] {
137+
getAncestorScrollContainers(elementOrElementRef: ElementRef|HTMLElement): CdkScrollable[] {
135138
const scrollingContainers: CdkScrollable[] = [];
136139

137140
this.scrollContainers.forEach((_subscription: Subscription, scrollable: CdkScrollable) => {
138-
if (this._scrollableContainsElement(scrollable, elementRef)) {
141+
if (this._scrollableContainsElement(scrollable, elementOrElementRef)) {
139142
scrollingContainers.push(scrollable);
140143
}
141144
});
@@ -149,8 +152,10 @@ export class ScrollDispatcher implements OnDestroy {
149152
}
150153

151154
/** Returns true if the element is contained within the provided Scrollable. */
152-
private _scrollableContainsElement(scrollable: CdkScrollable, elementRef: ElementRef): boolean {
153-
let element: HTMLElement | null = elementRef.nativeElement;
155+
private _scrollableContainsElement(
156+
scrollable: CdkScrollable,
157+
elementOrElementRef: ElementRef|HTMLElement): boolean {
158+
let element: HTMLElement | null = coerceElement(elementOrElementRef);
154159
let scrollableElement = scrollable.getElementRef().nativeElement;
155160

156161
// Traverse through the element parents until we reach null, checking if any of the elements

tools/public_api_guard/cdk/scrolling.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ export declare class ScrollDispatcher implements OnDestroy {
170170
_globalSubscription: Subscription | null;
171171
scrollContainers: Map<CdkScrollable, Subscription>;
172172
constructor(_ngZone: NgZone, _platform: Platform, document: any);
173-
ancestorScrolled(elementRef: ElementRef, auditTimeInMs?: number): Observable<CdkScrollable | void>;
173+
ancestorScrolled(elementOrElementRef: ElementRef | HTMLElement, auditTimeInMs?: number): Observable<CdkScrollable | void>;
174174
deregister(scrollable: CdkScrollable): void;
175-
getAncestorScrollContainers(elementRef: ElementRef): CdkScrollable[];
175+
getAncestorScrollContainers(elementOrElementRef: ElementRef | HTMLElement): CdkScrollable[];
176176
ngOnDestroy(): void;
177177
register(scrollable: CdkScrollable): void;
178178
scrolled(auditTimeInMs?: number): Observable<CdkScrollable | void>;

yarn.lock

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8812,6 +8812,23 @@ meow@^8.0.0:
88128812
type-fest "^0.18.0"
88138813
yargs-parser "^20.2.3"
88148814

8815+
meow@^8.0.0:
8816+
version "8.0.0"
8817+
resolved "https://registry.yarnpkg.com/meow/-/meow-8.0.0.tgz#1aa10ee61046719e334ffdc038bb5069250ec99a"
8818+
integrity sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==
8819+
dependencies:
8820+
"@types/minimist" "^1.2.0"
8821+
camelcase-keys "^6.2.2"
8822+
decamelize-keys "^1.1.0"
8823+
hard-rejection "^2.1.0"
8824+
minimist-options "4.1.0"
8825+
normalize-package-data "^3.0.0"
8826+
read-pkg-up "^7.0.1"
8827+
redent "^3.0.0"
8828+
trim-newlines "^3.0.0"
8829+
type-fest "^0.18.0"
8830+
yargs-parser "^20.2.3"
8831+
88158832
88168833
version "1.0.1"
88178834
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@@ -12787,6 +12804,11 @@ type-fest@^0.18.0:
1278712804
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
1278812805
integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
1278912806

12807+
type-fest@^0.18.0:
12808+
version "0.18.1"
12809+
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
12810+
integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
12811+
1279012812
type-fest@^0.6.0:
1279112813
version "0.6.0"
1279212814
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"

0 commit comments

Comments
 (0)