Skip to content

Commit a943b36

Browse files
crisbetotinayuangao
authored andcommitted
feat(snack-bar): add injection token for overriding the default options (#9849)
Adds the `MAT_SNACK_BAR_DEFAULT_OPTIONS` injection token that allows consumers to set the default snack bar options globally. Fixes #9821.
1 parent ccbab87 commit a943b36

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

src/lib/snack-bar/snack-bar-module.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ import {PortalModule} from '@angular/cdk/portal';
1313
import {LIVE_ANNOUNCER_PROVIDER} from '@angular/cdk/a11y';
1414
import {LayoutModule} from '@angular/cdk/layout';
1515
import {MatCommonModule} from '@angular/material/core';
16-
import {MatSnackBar} from './snack-bar';
16+
import {MatSnackBar, MAT_SNACK_BAR_DEFAULT_OPTIONS} from './snack-bar';
1717
import {MatSnackBarContainer} from './snack-bar-container';
18+
import {MatSnackBarConfig} from './snack-bar-config';
1819
import {SimpleSnackBar} from './simple-snack-bar';
1920

2021

22+
/** @docs-private */
23+
export function MAT_SNACK_BAR_DEFAULT_OPTIONS_PROVIDER_FACTORY() {
24+
return new MatSnackBarConfig();
25+
}
26+
2127
@NgModule({
2228
imports: [
2329
OverlayModule,
@@ -29,6 +35,13 @@ import {SimpleSnackBar} from './simple-snack-bar';
2935
exports: [MatSnackBarContainer, MatCommonModule],
3036
declarations: [MatSnackBarContainer, SimpleSnackBar],
3137
entryComponents: [MatSnackBarContainer, SimpleSnackBar],
32-
providers: [MatSnackBar, LIVE_ANNOUNCER_PROVIDER]
38+
providers: [
39+
MatSnackBar,
40+
LIVE_ANNOUNCER_PROVIDER,
41+
{
42+
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
43+
useFactory: MAT_SNACK_BAR_DEFAULT_OPTIONS_PROVIDER_FACTORY
44+
},
45+
]
3346
})
3447
export class MatSnackBarModule {}

src/lib/snack-bar/snack-bar.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ export class MessageArchivedComponent {
7272
constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any) { }
7373
}
7474
```
75+
76+
### Setting the global configuration defaults
77+
If you want to override the default snack bar options, you can do so using the
78+
`MAT_SNACK_BAR_DEFAULT_OPTIONS` injection token.
79+
80+
```ts
81+
@NgModule({
82+
providers: [
83+
{provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: {duration: 2500}}
84+
]
85+
})
86+
```
87+
7588
### Accessibility
7689
Snack-bar messages are announced via an `aria-live` region. Focus is not moved to
7790
the snack-bar element, as this would be disruptive to a user in the middle of a

src/lib/snack-bar/snack-bar.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
MatSnackBarRef,
1919
SimpleSnackBar,
2020
MAT_SNACK_BAR_DATA,
21+
MAT_SNACK_BAR_DEFAULT_OPTIONS,
2122
} from './index';
2223

2324
describe('MatSnackBar', () => {
@@ -387,6 +388,32 @@ describe('MatSnackBar', () => {
387388
expect(pane.getAttribute('dir')).toBe('rtl', 'Expected the pane to be in RTL mode.');
388389
});
389390

391+
it('should be able to override the default config', fakeAsync(() => {
392+
overlayContainer.ngOnDestroy();
393+
viewContainerFixture.destroy();
394+
395+
TestBed
396+
.resetTestingModule()
397+
.overrideProvider(MAT_SNACK_BAR_DEFAULT_OPTIONS, {
398+
deps: [],
399+
useFactory: () => ({panelClass: 'custom-class'})
400+
})
401+
.configureTestingModule({imports: [MatSnackBarModule, NoopAnimationsModule]})
402+
.compileComponents();
403+
404+
inject([MatSnackBar, OverlayContainer], (sb: MatSnackBar, oc: OverlayContainer) => {
405+
snackBar = sb;
406+
overlayContainer = oc;
407+
overlayContainerElement = oc.getContainerElement();
408+
})();
409+
410+
snackBar.open(simpleMessage);
411+
flush();
412+
413+
expect(overlayContainerElement.querySelector('snack-bar-container')!.classList)
414+
.toContain('custom-class', 'Expected class applied through the defaults to be applied.');
415+
}));
416+
390417
describe('with custom component', () => {
391418
it('should open a custom component', () => {
392419
const snackBarRef = snackBar.openFromComponent(BurritosNotification);
@@ -504,7 +531,6 @@ describe('MatSnackBar with parent MatSnackBar', () => {
504531
}));
505532
});
506533

507-
508534
describe('MatSnackBar Positioning', () => {
509535
let snackBar: MatSnackBar;
510536
let liveAnnouncer: LiveAnnouncer;

src/lib/snack-bar/snack-bar.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@ import {LiveAnnouncer} from '@angular/cdk/a11y';
1010
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';
1111
import {Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay';
1212
import {ComponentPortal, ComponentType, PortalInjector} from '@angular/cdk/portal';
13-
import {ComponentRef, Injectable, Injector, Optional, SkipSelf} from '@angular/core';
13+
import {
14+
ComponentRef,
15+
Inject,
16+
Injectable,
17+
Injector,
18+
InjectionToken,
19+
Optional,
20+
SkipSelf,
21+
} from '@angular/core';
1422
import {take} from 'rxjs/operators/take';
1523
import {takeUntil} from 'rxjs/operators/takeUntil';
1624
import {SimpleSnackBar} from './simple-snack-bar';
@@ -19,6 +27,10 @@ import {MatSnackBarContainer} from './snack-bar-container';
1927
import {MatSnackBarRef} from './snack-bar-ref';
2028

2129

30+
/** Injection token that can be used to specify default snack bar. */
31+
export const MAT_SNACK_BAR_DEFAULT_OPTIONS =
32+
new InjectionToken<MatSnackBarConfig>('mat-snack-bar-default-options');
33+
2234
/**
2335
* Service to dispatch Material Design snack bar messages.
2436
*/
@@ -50,7 +62,8 @@ export class MatSnackBar {
5062
private _live: LiveAnnouncer,
5163
private _injector: Injector,
5264
private _breakpointObserver: BreakpointObserver,
53-
@Optional() @SkipSelf() private _parentSnackBar: MatSnackBar) {}
65+
@Optional() @SkipSelf() private _parentSnackBar: MatSnackBar,
66+
@Inject(MAT_SNACK_BAR_DEFAULT_OPTIONS) private _defaultConfig: MatSnackBarConfig) {}
5467

5568
/**
5669
* Creates and dispatches a snack bar with a custom component for the content, removing any
@@ -60,7 +73,7 @@ export class MatSnackBar {
6073
* @param config Extra configuration for the snack bar.
6174
*/
6275
openFromComponent<T>(component: ComponentType<T>, config?: MatSnackBarConfig): MatSnackBarRef<T> {
63-
const _config = _applyConfigDefaults(config);
76+
const _config = {...this._defaultConfig, ...config};
6477
const snackBarRef = this._attach(component, _config);
6578

6679
// When the snackbar is dismissed, clear the reference to it.
@@ -104,7 +117,7 @@ export class MatSnackBar {
104117
*/
105118
open(message: string, action: string = '', config?: MatSnackBarConfig):
106119
MatSnackBarRef<SimpleSnackBar> {
107-
const _config = _applyConfigDefaults(config);
120+
const _config = {...this._defaultConfig, ...config};
108121

109122
// Since the user doesn't have access to the component, we can
110123
// override the data to pass in our own message and action.
@@ -216,12 +229,3 @@ export class MatSnackBar {
216229
return new PortalInjector(userInjector || this._injector, injectionTokens);
217230
}
218231
}
219-
220-
/**
221-
* Applies default options to the snackbar config.
222-
* @param config The configuration to which the defaults will be applied.
223-
* @returns The new configuration object with defaults applied.
224-
*/
225-
function _applyConfigDefaults(config?: MatSnackBarConfig): MatSnackBarConfig {
226-
return {...new MatSnackBarConfig(), ...config};
227-
}

0 commit comments

Comments
 (0)