fix(bottom-sheet): close on page navigation (#12106)

Similarly to the dialog, closes the bottom sheet when the user navigates to another page. The behavior can be opted out of.
This commit is contained in:
Kristiyan Kostadinov
2018-07-12 16:45:27 +02:00
committed by Jeremy Elbourn
parent fcc887535b
commit 5c6f25e053
4 changed files with 71 additions and 7 deletions
@@ -39,4 +39,7 @@ export class MatBottomSheetConfig<D = any> {
/** Aria label to assign to the bottom sheet element. */
ariaLabel?: string | null = null;
/** Whether the bottom sheet should close when the user goes backwards/forwards in history. */
closeOnNavigation?: boolean = true;
}
+18 -2
View File
@@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Location} from '@angular/common';
import {ESCAPE} from '@angular/cdk/keycodes';
import {OverlayRef} from '@angular/cdk/overlay';
import {merge, Observable, Subject} from 'rxjs';
import {merge, Observable, Subject, SubscriptionLike, Subscription} from 'rxjs';
import {filter, take} from 'rxjs/operators';
import {MatBottomSheetContainer} from './bottom-sheet-container';
@@ -35,7 +36,13 @@ export class MatBottomSheetRef<T = any, R = any> {
/** Result to be passed down to the `afterDismissed` stream. */
private _result: R | undefined;
constructor(containerInstance: MatBottomSheetContainer, private _overlayRef: OverlayRef) {
/** Subscription to changes in the user's location. */
private _locationChanges: SubscriptionLike = Subscription.EMPTY;
constructor(
containerInstance: MatBottomSheetContainer,
private _overlayRef: OverlayRef,
location?: Location) {
this.containerInstance = containerInstance;
// Emit when opening animation completes
@@ -54,6 +61,7 @@ export class MatBottomSheetRef<T = any, R = any> {
take(1)
)
.subscribe(() => {
this._locationChanges.unsubscribe();
this._overlayRef.dispose();
this._afterDismissed.next(this._result);
this._afterDismissed.complete();
@@ -65,6 +73,14 @@ export class MatBottomSheetRef<T = any, R = any> {
_overlayRef.keydownEvents().pipe(filter(event => event.keyCode === ESCAPE))
).subscribe(() => this.dismiss());
}
if (location) {
this._locationChanges = location.subscribe(() => {
if (containerInstance.bottomSheetConfig.closeOnNavigation) {
this.dismiss();
}
});
}
}
/**
+46 -3
View File
@@ -21,6 +21,8 @@ import {
TestBed,
tick,
} from '@angular/core/testing';
import {Location} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MatBottomSheet} from './bottom-sheet';
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetConfig} from './bottom-sheet-config';
@@ -36,19 +38,24 @@ describe('MatBottomSheet', () => {
let testViewContainerRef: ViewContainerRef;
let viewContainerFixture: ComponentFixture<ComponentWithChildViewContainer>;
let mockLocation: SpyLocation;
beforeEach(fakeAsync(() => {
TestBed
.configureTestingModule({imports: [MatBottomSheetModule, BottomSheetTestModule]})
.configureTestingModule({
imports: [MatBottomSheetModule, BottomSheetTestModule],
providers: [{provide: Location, useClass: SpyLocation}]
})
.compileComponents();
}));
beforeEach(inject([MatBottomSheet, OverlayContainer, ViewportRuler],
(bs: MatBottomSheet, oc: OverlayContainer, vr: ViewportRuler) => {
beforeEach(inject([MatBottomSheet, OverlayContainer, ViewportRuler, Location],
(bs: MatBottomSheet, oc: OverlayContainer, vr: ViewportRuler, l: Location) => {
bottomSheet = bs;
overlayContainer = oc;
viewportRuler = vr;
overlayContainerElement = oc.getContainerElement();
mockLocation = l as SpyLocation;
}));
afterEach(() => {
@@ -349,6 +356,42 @@ describe('MatBottomSheet', () => {
expect(spy).toHaveBeenCalledWith(1337);
}));
it('should close the bottom sheet when going forwards/backwards in history', fakeAsync(() => {
bottomSheet.open(PizzaMsg);
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeTruthy();
mockLocation.simulateUrlPop('');
viewContainerFixture.detectChanges();
flush();
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeFalsy();
}));
it('should close the bottom sheet when the location hash changes', fakeAsync(() => {
bottomSheet.open(PizzaMsg);
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeTruthy();
mockLocation.simulateHashChange('');
viewContainerFixture.detectChanges();
flush();
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeFalsy();
}));
it('should allow the consumer to disable closing a bottom sheet on navigation', fakeAsync(() => {
bottomSheet.open(PizzaMsg, {closeOnNavigation: false});
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeTruthy();
mockLocation.simulateUrlPop('');
viewContainerFixture.detectChanges();
flush();
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeTruthy();
}));
describe('passing in data', () => {
it('should be able to pass in data', () => {
const config = {
+4 -2
View File
@@ -10,6 +10,7 @@ import {Directionality} from '@angular/cdk/bidi';
import {Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay';
import {ComponentPortal, ComponentType, PortalInjector, TemplatePortal} from '@angular/cdk/portal';
import {ComponentRef, Injectable, Injector, Optional, SkipSelf, TemplateRef} from '@angular/core';
import {Location} from '@angular/common';
import {of as observableOf} from 'rxjs';
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetConfig} from './bottom-sheet-config';
import {MatBottomSheetContainer} from './bottom-sheet-container';
@@ -41,7 +42,8 @@ export class MatBottomSheet {
constructor(
private _overlay: Overlay,
private _injector: Injector,
@Optional() @SkipSelf() private _parentBottomSheet: MatBottomSheet) {}
@Optional() @SkipSelf() private _parentBottomSheet: MatBottomSheet,
@Optional() private _location?: Location) {}
open<T, D = any, R = any>(component: ComponentType<T>,
config?: MatBottomSheetConfig<D>): MatBottomSheetRef<T, R>;
@@ -54,7 +56,7 @@ export class MatBottomSheet {
const _config = _applyConfigDefaults(config);
const overlayRef = this._createOverlay(_config);
const container = this._attachContainer(overlayRef, _config);
const ref = new MatBottomSheetRef<T, R>(container, overlayRef);
const ref = new MatBottomSheetRef<T, R>(container, overlayRef, this._location);
if (componentOrTemplateRef instanceof TemplateRef) {
container.attachTemplatePortal(new TemplatePortal<T>(componentOrTemplateRef, null!, {