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.
This commit is contained in:
Kristiyan Kostadinov
2018-03-03 00:47:03 +02:00
committed by tinayuangao
parent ccbab877c3
commit a943b36c7b
4 changed files with 72 additions and 16 deletions
+15 -2
View File
@@ -13,11 +13,17 @@ import {PortalModule} from '@angular/cdk/portal';
import {LIVE_ANNOUNCER_PROVIDER} from '@angular/cdk/a11y';
import {LayoutModule} from '@angular/cdk/layout';
import {MatCommonModule} from '@angular/material/core';
import {MatSnackBar} from './snack-bar';
import {MatSnackBar, MAT_SNACK_BAR_DEFAULT_OPTIONS} from './snack-bar';
import {MatSnackBarContainer} from './snack-bar-container';
import {MatSnackBarConfig} from './snack-bar-config';
import {SimpleSnackBar} from './simple-snack-bar';
/** @docs-private */
export function MAT_SNACK_BAR_DEFAULT_OPTIONS_PROVIDER_FACTORY() {
return new MatSnackBarConfig();
}
@NgModule({
imports: [
OverlayModule,
@@ -29,6 +35,13 @@ import {SimpleSnackBar} from './simple-snack-bar';
exports: [MatSnackBarContainer, MatCommonModule],
declarations: [MatSnackBarContainer, SimpleSnackBar],
entryComponents: [MatSnackBarContainer, SimpleSnackBar],
providers: [MatSnackBar, LIVE_ANNOUNCER_PROVIDER]
providers: [
MatSnackBar,
LIVE_ANNOUNCER_PROVIDER,
{
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
useFactory: MAT_SNACK_BAR_DEFAULT_OPTIONS_PROVIDER_FACTORY
},
]
})
export class MatSnackBarModule {}
+13
View File
@@ -72,6 +72,19 @@ export class MessageArchivedComponent {
constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any) { }
}
```
### Setting the global configuration defaults
If you want to override the default snack bar options, you can do so using the
`MAT_SNACK_BAR_DEFAULT_OPTIONS` injection token.
```ts
@NgModule({
providers: [
{provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: {duration: 2500}}
]
})
```
### Accessibility
Snack-bar messages are announced via an `aria-live` region. Focus is not moved to
the snack-bar element, as this would be disruptive to a user in the middle of a
+27 -1
View File
@@ -18,6 +18,7 @@ import {
MatSnackBarRef,
SimpleSnackBar,
MAT_SNACK_BAR_DATA,
MAT_SNACK_BAR_DEFAULT_OPTIONS,
} from './index';
describe('MatSnackBar', () => {
@@ -387,6 +388,32 @@ describe('MatSnackBar', () => {
expect(pane.getAttribute('dir')).toBe('rtl', 'Expected the pane to be in RTL mode.');
});
it('should be able to override the default config', fakeAsync(() => {
overlayContainer.ngOnDestroy();
viewContainerFixture.destroy();
TestBed
.resetTestingModule()
.overrideProvider(MAT_SNACK_BAR_DEFAULT_OPTIONS, {
deps: [],
useFactory: () => ({panelClass: 'custom-class'})
})
.configureTestingModule({imports: [MatSnackBarModule, NoopAnimationsModule]})
.compileComponents();
inject([MatSnackBar, OverlayContainer], (sb: MatSnackBar, oc: OverlayContainer) => {
snackBar = sb;
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
})();
snackBar.open(simpleMessage);
flush();
expect(overlayContainerElement.querySelector('snack-bar-container')!.classList)
.toContain('custom-class', 'Expected class applied through the defaults to be applied.');
}));
describe('with custom component', () => {
it('should open a custom component', () => {
const snackBarRef = snackBar.openFromComponent(BurritosNotification);
@@ -504,7 +531,6 @@ describe('MatSnackBar with parent MatSnackBar', () => {
}));
});
describe('MatSnackBar Positioning', () => {
let snackBar: MatSnackBar;
let liveAnnouncer: LiveAnnouncer;
+17 -13
View File
@@ -10,7 +10,15 @@ import {LiveAnnouncer} from '@angular/cdk/a11y';
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';
import {Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay';
import {ComponentPortal, ComponentType, PortalInjector} from '@angular/cdk/portal';
import {ComponentRef, Injectable, Injector, Optional, SkipSelf} from '@angular/core';
import {
ComponentRef,
Inject,
Injectable,
Injector,
InjectionToken,
Optional,
SkipSelf,
} from '@angular/core';
import {take} from 'rxjs/operators/take';
import {takeUntil} from 'rxjs/operators/takeUntil';
import {SimpleSnackBar} from './simple-snack-bar';
@@ -19,6 +27,10 @@ import {MatSnackBarContainer} from './snack-bar-container';
import {MatSnackBarRef} from './snack-bar-ref';
/** Injection token that can be used to specify default snack bar. */
export const MAT_SNACK_BAR_DEFAULT_OPTIONS =
new InjectionToken<MatSnackBarConfig>('mat-snack-bar-default-options');
/**
* Service to dispatch Material Design snack bar messages.
*/
@@ -50,7 +62,8 @@ export class MatSnackBar {
private _live: LiveAnnouncer,
private _injector: Injector,
private _breakpointObserver: BreakpointObserver,
@Optional() @SkipSelf() private _parentSnackBar: MatSnackBar) {}
@Optional() @SkipSelf() private _parentSnackBar: MatSnackBar,
@Inject(MAT_SNACK_BAR_DEFAULT_OPTIONS) private _defaultConfig: MatSnackBarConfig) {}
/**
* Creates and dispatches a snack bar with a custom component for the content, removing any
@@ -60,7 +73,7 @@ export class MatSnackBar {
* @param config Extra configuration for the snack bar.
*/
openFromComponent<T>(component: ComponentType<T>, config?: MatSnackBarConfig): MatSnackBarRef<T> {
const _config = _applyConfigDefaults(config);
const _config = {...this._defaultConfig, ...config};
const snackBarRef = this._attach(component, _config);
// When the snackbar is dismissed, clear the reference to it.
@@ -104,7 +117,7 @@ export class MatSnackBar {
*/
open(message: string, action: string = '', config?: MatSnackBarConfig):
MatSnackBarRef<SimpleSnackBar> {
const _config = _applyConfigDefaults(config);
const _config = {...this._defaultConfig, ...config};
// Since the user doesn't have access to the component, we can
// override the data to pass in our own message and action.
@@ -216,12 +229,3 @@ export class MatSnackBar {
return new PortalInjector(userInjector || this._injector, injectionTokens);
}
}
/**
* Applies default options to the snackbar config.
* @param config The configuration to which the defaults will be applied.
* @returns The new configuration object with defaults applied.
*/
function _applyConfigDefaults(config?: MatSnackBarConfig): MatSnackBarConfig {
return {...new MatSnackBarConfig(), ...config};
}