Skip to content

Commit 766faa1

Browse files
crisbetokara
authored andcommitted
refactor(scroll-dispatcher): remove the need to pass in a callback to the scrolled method (#6679)
1 parent 0834a31 commit 766faa1

9 files changed

+52
-69
lines changed

src/cdk/overlay/scroll/close-scroll-strategy.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ describe('CloseScrollStrategy', () => {
2121
TestBed.configureTestingModule({
2222
imports: [OverlayModule, PortalModule, OverlayTestModule],
2323
providers: [
24-
{provide: ScrollDispatcher, useFactory: () => {
25-
return {scrolled: (_delay: number, callback: () => any) => {
26-
return scrolledSubject.asObservable().subscribe(callback);
27-
}};
28-
}}
24+
{provide: ScrollDispatcher, useFactory: () => ({
25+
scrolled: () => scrolledSubject.asObservable()
26+
})}
2927
]
3028
});
3129

src/cdk/overlay/scroll/close-scroll-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class CloseScrollStrategy implements ScrollStrategy {
3131

3232
enable() {
3333
if (!this._scrollSubscription) {
34-
this._scrollSubscription = this._scrollDispatcher.scrolled(0, () => {
34+
this._scrollSubscription = this._scrollDispatcher.scrolled(0).subscribe(() => {
3535
if (this._overlayRef.hasAttached()) {
3636
this._overlayRef.detach();
3737
}

src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ describe('RepositionScrollStrategy', () => {
2121
TestBed.configureTestingModule({
2222
imports: [OverlayModule, PortalModule, OverlayTestModule],
2323
providers: [
24-
{provide: ScrollDispatcher, useFactory: () => {
25-
return {scrolled: (_delay: number, callback: () => any) => {
26-
return scrolledSubject.asObservable().subscribe(callback);
27-
}};
28-
}}
24+
{provide: ScrollDispatcher, useFactory: () => ({
25+
scrolled: () => scrolledSubject.asObservable()
26+
})}
2927
]
3028
});
3129

src/cdk/overlay/scroll/reposition-scroll-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class RepositionScrollStrategy implements ScrollStrategy {
4141
if (!this._scrollSubscription) {
4242
let throttle = this._config ? this._config.scrollThrottle : 0;
4343

44-
this._scrollSubscription = this._scrollDispatcher.scrolled(throttle, () => {
44+
this._scrollSubscription = this._scrollDispatcher.scrolled(throttle).subscribe(() => {
4545
this._overlayRef.updatePosition();
4646
});
4747
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('Scroll Dispatcher', () => {
4747
// Listen for notifications from scroll service with a throttle of 100ms
4848
const throttleTime = 100;
4949
const serviceSpy = jasmine.createSpy('service scroll callback');
50-
scroll.scrolled(throttleTime, serviceSpy);
50+
scroll.scrolled(throttleTime).subscribe(serviceSpy);
5151

5252
// Emit a scroll event from the scrolling element in our component.
5353
// This event should be picked up by the scrollable directive and notify.
@@ -70,7 +70,7 @@ describe('Scroll Dispatcher', () => {
7070
const spy = jasmine.createSpy('zone unstable callback');
7171
const subscription = fixture.ngZone!.onUnstable.subscribe(spy);
7272

73-
scroll.scrolled(0, () => {});
73+
scroll.scrolled(0).subscribe(() => {});
7474
dispatchFakeEvent(document, 'scroll');
7575

7676
expect(spy).not.toHaveBeenCalled();
@@ -89,7 +89,7 @@ describe('Scroll Dispatcher', () => {
8989

9090
it('should be able to unsubscribe from the global scrollable', () => {
9191
const spy = jasmine.createSpy('global scroll callback');
92-
const subscription = scroll.scrolled(0, spy);
92+
const subscription = scroll.scrolled(0).subscribe(spy);
9393

9494
dispatchFakeEvent(document, 'scroll');
9595
expect(spy).toHaveBeenCalledTimes(1);
@@ -132,7 +132,7 @@ describe('Scroll Dispatcher', () => {
132132
it('should lazily add global listeners as service subscriptions are added and removed', () => {
133133
expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.');
134134

135-
const subscription = scroll.scrolled(0, () => {});
135+
const subscription = scroll.scrolled(0).subscribe(() => {});
136136

137137
expect(scroll._globalSubscription).toBeTruthy(
138138
'Expected global listeners after a subscription has been added.');

src/cdk/scrolling/scroll-dispatcher.ts

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {ElementRef, Injectable, NgZone, Optional, SkipSelf} from '@angular/core'
1010
import {Platform} from '@angular/cdk/platform';
1111
import {Subject} from 'rxjs/Subject';
1212
import {Subscription} from 'rxjs/Subscription';
13+
import {Observable} from 'rxjs/Observable';
1314
import {fromEvent} from 'rxjs/observable/fromEvent';
15+
import {of as observableOf} from 'rxjs/observable/of';
1416
import {auditTime} from 'rxjs/operator/auditTime';
1517
import {Scrollable} from './scrollable';
1618

@@ -27,7 +29,7 @@ export class ScrollDispatcher {
2729
constructor(private _ngZone: NgZone, private _platform: Platform) { }
2830

2931
/** Subject for notifying that a registered scrollable reference element has been scrolled. */
30-
_scrolled: Subject<void> = new Subject<void>();
32+
private _scrolled: Subject<void> = new Subject<void>();
3133

3234
/** Keeps track of the global `scroll` and `resize` subscriptions. */
3335
_globalSubscription: Subscription | null = null;
@@ -47,8 +49,7 @@ export class ScrollDispatcher {
4749
* @param scrollable Scrollable instance to be registered.
4850
*/
4951
register(scrollable: Scrollable): void {
50-
const scrollSubscription = scrollable.elementScrolled().subscribe(() => this._notify());
51-
52+
const scrollSubscription = scrollable.elementScrolled().subscribe(() => this._scrolled.next());
5253
this.scrollableReferences.set(scrollable, scrollSubscription);
5354
}
5455

@@ -66,44 +67,34 @@ export class ScrollDispatcher {
6667
}
6768

6869
/**
69-
* Subscribes to an observable that emits an event whenever any of the registered Scrollable
70+
* Returns an observable that emits an event whenever any of the registered Scrollable
7071
* references (or window, document, or body) fire a scrolled event. Can provide a time in ms
7172
* to override the default "throttle" time.
7273
*/
73-
scrolled(auditTimeInMs: number = DEFAULT_SCROLL_TIME, callback: () => any): Subscription {
74-
// Scroll events can only happen on the browser, so do nothing if we're not on the browser.
75-
if (!this._platform.isBrowser) {
76-
return Subscription.EMPTY;
77-
}
78-
79-
// In the case of a 0ms delay, use an observable without auditTime
80-
// since it does add a perceptible delay in processing overhead.
81-
let observable = auditTimeInMs > 0 ?
82-
auditTime.call(this._scrolled.asObservable(), auditTimeInMs) :
83-
this._scrolled.asObservable();
84-
85-
this._scrolledCount++;
86-
87-
if (!this._globalSubscription) {
88-
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
89-
return fromEvent(window.document, 'scroll').subscribe(() => this._notify());
90-
});
91-
}
74+
scrolled(auditTimeInMs: number = DEFAULT_SCROLL_TIME): Observable<void> {
75+
return this._platform.isBrowser ? Observable.create(observer => {
76+
if (!this._globalSubscription) {
77+
this._addGlobalListener();
78+
}
9279

93-
// Note that we need to do the subscribing from here, in order to be able to remove
94-
// the global event listeners once there are no more subscriptions.
95-
let subscription = observable.subscribe(callback);
80+
// In the case of a 0ms delay, use an observable without auditTime
81+
// since it does add a perceptible delay in processing overhead.
82+
const subscription = auditTimeInMs > 0 ?
83+
auditTime.call(this._scrolled, auditTimeInMs).subscribe(observer) :
84+
this._scrolled.subscribe(observer);
9685

97-
subscription.add(() => {
98-
this._scrolledCount--;
86+
this._scrolledCount++;
9987

100-
if (this._globalSubscription && !this.scrollableReferences.size && !this._scrolledCount) {
101-
this._globalSubscription.unsubscribe();
102-
this._globalSubscription = null;
103-
}
104-
});
88+
return () => {
89+
subscription.unsubscribe();
90+
this._scrolledCount--;
10591

106-
return subscription;
92+
if (this._globalSubscription && !this.scrollableReferences.size && !this._scrolledCount) {
93+
this._globalSubscription.unsubscribe();
94+
this._globalSubscription = null;
95+
}
96+
};
97+
}) : observableOf<void>();
10798
}
10899

109100
/** Returns all registered Scrollables that contain the provided element. */
@@ -133,9 +124,11 @@ export class ScrollDispatcher {
133124
return false;
134125
}
135126

136-
/** Sends a notification that a scroll event has been fired. */
137-
_notify() {
138-
this._scrolled.next();
127+
/** Sets up the global scroll and resize listeners. */
128+
private _addGlobalListener() {
129+
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
130+
return fromEvent(window.document, 'scroll').subscribe(() => this._scrolled.next());
131+
});
139132
}
140133
}
141134

src/cdk/scrolling/viewport-ruler.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,20 @@ export class ViewportRuler implements OnDestroy {
3333
private _change: Observable<Event>;
3434

3535
/** Subscriptions to streams that invalidate the cached viewport dimensions. */
36-
private _invalidateCacheSubscriptions: Subscription[];
36+
private _invalidateCacheSubscription = Subscription.EMPTY;
3737

3838
constructor(platform: Platform, ngZone: NgZone, scrollDispatcher: ScrollDispatcher) {
3939
this._change = platform.isBrowser ? ngZone.runOutsideAngular(() => {
4040
return merge<Event>(fromEvent(window, 'resize'), fromEvent(window, 'orientationchange'));
4141
}) : observableOf();
4242

4343
// Subscribe to scroll and resize events and update the document rectangle on changes.
44-
this._invalidateCacheSubscriptions = [
45-
scrollDispatcher.scrolled(0, () => this._cacheViewportGeometry()),
46-
this.change().subscribe(() => this._cacheViewportGeometry())
47-
];
44+
this._invalidateCacheSubscription = merge(scrollDispatcher.scrolled(0), this.change())
45+
.subscribe(() => this._cacheViewportGeometry());
4846
}
4947

5048
ngOnDestroy() {
51-
this._invalidateCacheSubscriptions.forEach(subscription => subscription.unsubscribe());
49+
this._invalidateCacheSubscription.unsubscribe();
5250
}
5351

5452
/** Gets a ClientRect for the viewport's bounds. */

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,9 @@ describe('MatAutocomplete', () => {
8080
return {getContainerElement: () => overlayContainerElement};
8181
}},
8282
{provide: Directionality, useFactory: () => ({value: dir})},
83-
{provide: ScrollDispatcher, useFactory: () => {
84-
return {scrolled: (_delay: number, callback: () => any) => {
85-
return scrolledSubject.asObservable().subscribe(callback);
86-
}};
87-
}}
83+
{provide: ScrollDispatcher, useFactory: () => ({
84+
scrolled: () => scrolledSubject.asObservable()
85+
})}
8886
]
8987
});
9088

src/lib/select/select.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,9 @@ describe('MatSelect', () => {
114114
return {getContainerElement: () => overlayContainerElement};
115115
}},
116116
{provide: Directionality, useFactory: () => dir = { value: 'ltr' }},
117-
{provide: ScrollDispatcher, useFactory: () => {
118-
return {scrolled: (_delay: number, callback: () => any) => {
119-
return scrolledSubject.asObservable().subscribe(callback);
120-
}};
121-
}}
117+
{provide: ScrollDispatcher, useFactory: () => ({
118+
scrolled: () => scrolledSubject.asObservable()
119+
})}
122120
]
123121
});
124122

0 commit comments

Comments
 (0)