Skip to content

Commit 9b79ef6

Browse files
committed
refactor: switch to better approach
1 parent 3fe7dbf commit 9b79ef6

17 files changed

+93
-65
lines changed

src/e2e-app/block-scroll-strategy/block-scroll-strategy-e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ import {ScrollStrategyOptions, ScrollStrategy} from '@angular/material';
99
})
1010
export class BlockScrollStrategyE2E {
1111
constructor(private _scrollStrategyOptions: ScrollStrategyOptions) { }
12-
scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.get('block');
12+
scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
1313
}

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '@angular/core';
1414
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
1515
import {DOCUMENT} from '@angular/platform-browser';
16-
import {Overlay, OverlayRef, OverlayState, TemplatePortal, RepositionScrollStrategy} from '../core';
16+
import {Overlay, OverlayRef, OverlayState, TemplatePortal, ScrollStrategyOptions} from '../core';
1717
import {MdAutocomplete} from './autocomplete';
1818
import {PositionStrategy} from '../core/overlay/position/position-strategy';
1919
import {ConnectedPositionStrategy} from '../core/overlay/position/connected-position-strategy';
@@ -103,6 +103,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
103103
constructor(private _element: ElementRef, private _overlay: Overlay,
104104
private _viewContainerRef: ViewContainerRef,
105105
private _changeDetectorRef: ChangeDetectorRef,
106+
private _scrollStrategyOptions: ScrollStrategyOptions,
106107
@Optional() private _dir: Dir, private _zone: NgZone,
107108
@Optional() @Host() private _inputContainer: MdInputContainer,
108109
@Optional() @Inject(DOCUMENT) private _document: any) {}
@@ -366,7 +367,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
366367
overlayState.positionStrategy = this._getOverlayPosition();
367368
overlayState.width = this._getHostWidth();
368369
overlayState.direction = this._dir ? this._dir.value : 'ltr';
369-
overlayState.scrollStrategy = 'reposition';
370+
overlayState.scrollStrategy = this._scrollStrategyOptions.reposition;
370371
return overlayState;
371372
}
372373

src/lib/core/overlay/overlay-directives.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {PortalModule} from '../portal/portal-directives';
2525
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
2626
import {Dir, LayoutDirection} from '../rtl/dir';
2727
import {Scrollable} from './scroll/scrollable';
28-
import {RepositionScrollStrategy} from './scroll/reposition-scroll-strategy';
28+
import {ScrollStrategyOptions} from './scroll/scroll-strategy-options';
2929
import {ScrollStrategy} from './scroll/scroll-strategy';
3030
import {coerceBooleanProperty} from '../coercion/boolean-property';
3131
import {ESCAPE} from '../keyboard/keycodes';
@@ -124,7 +124,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
124124
@Input() backdropClass: string;
125125

126126
/** Strategy to be used when handling scroll events while the overlay is open. */
127-
@Input() scrollStrategy: OverlayStateScrollStrategy = 'reposition';
127+
@Input() scrollStrategy: OverlayStateScrollStrategy = this._scrollStrategyOptions.reposition;
128128

129129
/** Whether the overlay is open. */
130130
@Input() open: boolean = false;
@@ -156,6 +156,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
156156
constructor(
157157
private _overlay: Overlay,
158158
private _renderer: Renderer2,
159+
private _scrollStrategyOptions: ScrollStrategyOptions,
159160
templateRef: TemplateRef<any>,
160161
viewContainerRef: ViewContainerRef,
161162
@Optional() private _dir: Dir) {

src/lib/core/overlay/overlay-ref.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ export class OverlayRef implements PortalHost {
2323
private _scrollStrategy: ScrollStrategy,
2424
private _ngZone: NgZone) {
2525

26-
let scrollStrategyConfig = typeof _state.scrollStrategy === 'string' ?
27-
null :
28-
_state.scrollStrategy.config;
26+
let scrollStrategyConfig = null;
27+
28+
if (_state.scrollStrategy && typeof _state.scrollStrategy !== 'function') {
29+
scrollStrategyConfig = _state.scrollStrategy.config;
30+
}
2931

3032
_scrollStrategy.attach(this, scrollStrategyConfig);
3133
}

src/lib/core/overlay/overlay-state.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {PositionStrategy} from './position/position-strategy';
22
import {LayoutDirection} from '../rtl/dir';
3-
import {ScrollStrategy} from './scroll/scroll-strategy';
4-
import {NoopScrollStrategy} from './scroll/noop-scroll-strategy';
3+
import {ScrollStrategyOption} from './scroll/scroll-strategy-options';
54

6-
export type OverlayStateScrollStrategy = string | {name: string; config: any};
5+
export type OverlayStateScrollStrategy = {strategy: ScrollStrategyOption; config: any} |
6+
ScrollStrategyOption;
77

88
/**
99
* OverlayState is a bag of values for either the initial configuration or current state of an
@@ -14,7 +14,7 @@ export class OverlayState {
1414
positionStrategy: PositionStrategy;
1515

1616
/** Strategy to be used when handling scroll events while the overlay is open. */
17-
scrollStrategy: OverlayStateScrollStrategy = 'noop';
17+
scrollStrategy: OverlayStateScrollStrategy;
1818

1919
/** Whether the overlay has a backdrop. */
2020
hasBackdrop: boolean = false;

src/lib/core/overlay/overlay.spec.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ import {OverlayState} from './overlay-state';
88
import {OverlayRef} from './overlay-ref';
99
import {PositionStrategy} from './position/position-strategy';
1010
import {OverlayModule} from './overlay-directives';
11-
import {ScrollStrategy, ScrollStrategyOptions, ScrollDispatcher} from './scroll/index';
1211
import {ViewportRuler} from './position/viewport-ruler';
12+
import {
13+
ScrollStrategy,
14+
ScrollStrategyOptions,
15+
ScrollStrategyOption,
16+
ScrollDispatcher,
17+
} from './scroll/index';
1318

1419

1520
describe('Overlay', () => {
@@ -355,7 +360,7 @@ describe('Overlay', () => {
355360

356361
beforeEach(inject([ScrollStrategyOptions], (scrollOptions: ScrollStrategyOptionsOverride) => {
357362
config = new OverlayState();
358-
config.scrollStrategy = 'fake';
363+
config.scrollStrategy = scrollOptions.fake;
359364
overlayRef = overlay.create(config);
360365
fakeScrollStrategy =
361366
scrollOptions.instances[scrollOptions.instances.length - 1] as FakeScrollStrategy;
@@ -485,8 +490,8 @@ class ScrollStrategyOptionsOverride extends ScrollStrategyOptions {
485490
// used for accessing the current instance in unit tests.
486491
public instances: ScrollStrategy[] = [];
487492

488-
get(strategy: string): ScrollStrategy {
489-
let instance = strategy === 'fake' ? new FakeScrollStrategy() : super.get(strategy);
493+
fake: ScrollStrategyOption = () => {
494+
let instance = new FakeScrollStrategy();
490495
this.instances.push(instance);
491496
return instance;
492497
}

src/lib/core/overlay/overlay.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,24 @@ export class Overlay {
8686
* @param state
8787
*/
8888
private _createOverlayRef(pane: HTMLElement, state: OverlayState): OverlayRef {
89-
let scrollStrategyName = typeof state.scrollStrategy === 'string' ?
90-
state.scrollStrategy :
91-
state.scrollStrategy.name;
92-
93-
let scrollStrategy = this._scrollStrategyOptions.get(scrollStrategyName);
89+
let scrollStrategy = this._createScrollStrategy(state);
9490
let portalHost = this._createPortalHost(pane);
9591
return new OverlayRef(portalHost, pane, state, scrollStrategy, this._ngZone);
9692
}
93+
94+
/**
95+
* Creates a scroll strategy for the given overlay state.
96+
* @param state
97+
*/
98+
private _createScrollStrategy(state: OverlayState): ScrollStrategy {
99+
if (state.scrollStrategy) {
100+
return typeof state.scrollStrategy === 'function' ?
101+
state.scrollStrategy() :
102+
state.scrollStrategy.strategy();
103+
}
104+
105+
return this._scrollStrategyOptions.noop();
106+
}
97107
}
98108

99109
/** Providers for Overlay and its related injectables. */

src/lib/core/overlay/scroll/block-scroll-strategy.spec.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
OverlayState,
1010
Overlay,
1111
OverlayRef,
12+
ScrollStrategyOptions,
1213
} from '../../core';
1314

1415

@@ -25,19 +26,20 @@ describe('BlockScrollStrategy', () => {
2526
}).compileComponents();
2627
}));
2728

28-
beforeEach(inject([Overlay, ViewportRuler], (overlay: Overlay, viewportRuler: ViewportRuler) => {
29-
let overlayState = new OverlayState();
29+
beforeEach(inject([Overlay, ViewportRuler, ScrollStrategyOptions],
30+
(o: Overlay, v: ViewportRuler, sso: ScrollStrategyOptions) => {
31+
let overlayState = new OverlayState();
3032

31-
overlayState.scrollStrategy = 'block';
32-
overlayRef = overlay.create(overlayState);
33-
componentPortal = new ComponentPortal(FocacciaMsg);
33+
overlayState.scrollStrategy = sso.block;
34+
overlayRef = o.create(overlayState);
35+
componentPortal = new ComponentPortal(FocacciaMsg);
3436

35-
viewport = viewportRuler;
36-
forceScrollElement = document.createElement('div');
37-
document.body.appendChild(forceScrollElement);
38-
forceScrollElement.style.width = '100px';
39-
forceScrollElement.style.height = '3000px';
40-
}));
37+
viewport = v;
38+
forceScrollElement = document.createElement('div');
39+
document.body.appendChild(forceScrollElement);
40+
forceScrollElement.style.width = '100px';
41+
forceScrollElement.style.height = '3000px';
42+
}));
4143

4244
afterEach(() => {
4345
overlayRef.dispose();

src/lib/core/overlay/scroll/close-scroll-strategy.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
OverlayModule,
1111
ScrollStrategy,
1212
ScrollDispatcher,
13+
ScrollStrategyOptions,
1314
} from '../../core';
1415

1516

@@ -33,10 +34,10 @@ describe('CloseScrollStrategy', () => {
3334
TestBed.compileComponents();
3435
}));
3536

36-
beforeEach(inject([Overlay], (overlay: Overlay) => {
37+
beforeEach(inject([Overlay, ScrollStrategyOptions], (o: Overlay, sso: ScrollStrategyOptions) => {
3738
let overlayState = new OverlayState();
38-
overlayState.scrollStrategy = 'close';
39-
overlayRef = overlay.create(overlayState);
39+
overlayState.scrollStrategy = sso.close;
40+
overlayRef = o.create(overlayState);
4041
componentPortal = new ComponentPortal(MozarellaMsg);
4142
}));
4243

src/lib/core/overlay/scroll/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export {ScrollDispatcher} from './scroll-dispatcher';
99

1010
// Export pre-defined scroll strategies and interface to build custom ones.
1111
export {ScrollStrategy} from './scroll-strategy';
12-
export {ScrollStrategyOptions} from './scroll-strategy-options';
12+
export {ScrollStrategyOptions, ScrollStrategyOption} from './scroll-strategy-options';
1313
export {RepositionScrollStrategy} from './reposition-scroll-strategy';
1414
export {CloseScrollStrategy} from './close-scroll-strategy';
1515
export {NoopScrollStrategy} from './noop-scroll-strategy';

src/lib/core/overlay/scroll/reposition-scroll-strategy.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
OverlayModule,
1111
ScrollStrategy,
1212
ScrollDispatcher,
13+
ScrollStrategyOptions,
1314
} from '../../core';
1415

1516

@@ -33,10 +34,10 @@ describe('RepositionScrollStrategy', () => {
3334
TestBed.compileComponents();
3435
}));
3536

36-
beforeEach(inject([Overlay], (overlay: Overlay) => {
37+
beforeEach(inject([Overlay, ScrollStrategyOptions], (o: Overlay, sso: ScrollStrategyOptions) => {
3738
let overlayState = new OverlayState();
38-
overlayState.scrollStrategy = 'reposition';
39-
overlayRef = overlay.create(overlayState);
39+
overlayState.scrollStrategy = sso.reposition;
40+
overlayRef = o.create(overlayState);
4041
componentPortal = new ComponentPortal(PastaMsg);
4142
}));
4243

src/lib/core/overlay/scroll/scroll-strategy-options.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {BlockScrollStrategy} from './block-scroll-strategy';
77
import {ScrollDispatcher} from './scroll-dispatcher';
88
import {ViewportRuler} from '../position/viewport-ruler';
99

10+
export type ScrollStrategyOption = () => ScrollStrategy;
11+
1012

1113
/**
1214
* Factory that instantiates scroll strategies. Provides the built-in `reposition`, `close`,
@@ -18,14 +20,8 @@ export class ScrollStrategyOptions {
1820
private _scrollDispatcher: ScrollDispatcher,
1921
private _viewportRuler: ViewportRuler) { }
2022

21-
get(strategy: string): ScrollStrategy {
22-
switch (strategy) {
23-
case 'reposition': return new RepositionScrollStrategy(this._scrollDispatcher);
24-
case 'close': return new CloseScrollStrategy(this._scrollDispatcher);
25-
case 'noop': return new NoopScrollStrategy();
26-
case 'block': return new BlockScrollStrategy(this._viewportRuler);
27-
}
28-
29-
throw new Error(`Unsupported scroll strategy "${strategy}".`);
30-
}
23+
noop: ScrollStrategyOption = () => new NoopScrollStrategy();
24+
close: ScrollStrategyOption = () => new CloseScrollStrategy(this._scrollDispatcher);
25+
block: ScrollStrategyOption = () => new BlockScrollStrategy(this._viewportRuler);
26+
reposition: ScrollStrategyOption = () => new RepositionScrollStrategy(this._scrollDispatcher);
3127
}

src/lib/core/overlay/scroll/scroll-strategy.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ while the overlay is open. The strategy has a reference to the `OverlayRef`, all
66
recalculate the position, close the overlay, block scrolling, etc.
77

88
## Usage
9-
To associate an overlay with a scroll strategy, you have to pass in the name of the scroll strategy
10-
to the `OverlayState`. By default, all overlays will use the `noop` strategy which doesn't do
11-
anything. The other available strategies are `reposition`, `block` and `close`:
9+
To associate an overlay with a scroll strategy, you have to pass in a function, that returns a
10+
scroll strategy, to the `OverlayState`. By default, all overlays will use the `noop` strategy which
11+
doesn't do anything. The other available strategies are `reposition`, `block` and `close`:
1212

1313
```ts
1414
let overlayState = new OverlayState();
1515

16-
overlayState.scrollStrategy = 'block';
16+
overlayState.scrollStrategy = scrollStrategyOptions.block;
1717
this._overlay.create(overlayState).attach(yourPortal);
1818
```
1919

@@ -34,6 +34,7 @@ import {NgModule} from '@angular/core';
3434
import {
3535
ScrollStrategy,
3636
ScrollStrategyOptions,
37+
ScrollStrategyOption,
3738
ScrollDispatcher,
3839
ViewportRuler,
3940
} from '@angular/material';
@@ -49,13 +50,7 @@ class ScrollStrategyOptionsOverride extends ScrollStrategyOptions {
4950
super(scrollDispatcher, viewportRuler);
5051
}
5152

52-
get(strategy: string): ScrollStrategy {
53-
if (strategy === 'custom') {
54-
return new CustomScrollStrategy();
55-
}
56-
57-
return super.get(strategy);
58-
}
53+
custom: ScrollStrategyOption = () => new CustomScrollStrategy();
5954
}
6055

6156
// Register the provider with your module.

src/lib/datepicker/datepicker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {MdDatepickerInput} from './datepicker-input';
2525
import {Subscription} from 'rxjs/Subscription';
2626
import {MdDialogConfig} from '../dialog/dialog-config';
2727
import {DateAdapter} from '../core/datetime/index';
28+
import {ScrollStrategyOptions} from '../core/overlay/scroll/index';
2829
import {createMissingDateImplError} from './datepicker-errors';
2930
import {ESCAPE} from '../core/keyboard/keycodes';
3031
import {MdCalendar} from './calendar';
@@ -156,6 +157,7 @@ export class MdDatepicker<D> implements OnDestroy {
156157
private _overlay: Overlay,
157158
private _ngZone: NgZone,
158159
private _viewContainerRef: ViewContainerRef,
160+
private _scrollStrategyOptions: ScrollStrategyOptions,
159161
@Optional() private _dateAdapter: DateAdapter<D>,
160162
@Optional() private _dir: Dir) {
161163
if (!this._dateAdapter) {
@@ -267,7 +269,7 @@ export class MdDatepicker<D> implements OnDestroy {
267269
overlayState.hasBackdrop = true;
268270
overlayState.backdropClass = 'md-overlay-transparent-backdrop';
269271
overlayState.direction = this._dir ? this._dir.value : 'ltr';
270-
overlayState.scrollStrategy = 'reposition';
272+
overlayState.scrollStrategy = this._scrollStrategyOptions.reposition;
271273

272274
this._popupRef = this._overlay.create(overlayState);
273275
}

src/lib/dialog/dialog.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ import {Injector, ComponentRef, Injectable, Optional, SkipSelf, TemplateRef} fro
22
import {Location} from '@angular/common';
33
import {Observable} from 'rxjs/Observable';
44
import {Subject} from 'rxjs/Subject';
5-
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
5+
import {
6+
Overlay,
7+
OverlayRef,
8+
ComponentType,
9+
OverlayState,
10+
ComponentPortal,
11+
ScrollStrategyOptions,
12+
} from '../core';
613
import {extendObject} from '../core/util/object-extend';
714
import {ESCAPE} from '../core/keyboard/keycodes';
815
import {DialogInjector} from './dialog-injector';
@@ -48,6 +55,7 @@ export class MdDialog {
4855
constructor(
4956
private _overlay: Overlay,
5057
private _injector: Injector,
58+
private _scrollStrategyOptions: ScrollStrategyOptions,
5159
@Optional() private _location: Location,
5260
@Optional() @SkipSelf() private _parentDialog: MdDialog) {
5361

@@ -119,7 +127,7 @@ export class MdDialog {
119127
private _getOverlayState(dialogConfig: MdDialogConfig): OverlayState {
120128
let overlayState = new OverlayState();
121129
overlayState.hasBackdrop = dialogConfig.hasBackdrop;
122-
overlayState.scrollStrategy = 'block';
130+
overlayState.scrollStrategy = this._scrollStrategyOptions.block;
123131
if (dialogConfig.backdropClass) {
124132
overlayState.backdropClass = dialogConfig.backdropClass;
125133
}

0 commit comments

Comments
 (0)