mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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:
committed by
Jeremy Elbourn
parent
fcc887535b
commit
5c6f25e053
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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!, {
|
||||
|
||||
Reference in New Issue
Block a user