Skip to content

Commit 169a388

Browse files
committed
fix(bottomsheet): maintain multiple modal instances at the same time
Fixes #250
1 parent cf304b8 commit 169a388

File tree

1 file changed

+34
-35
lines changed

1 file changed

+34
-35
lines changed

src/bottomsheet/angular/bottomsheet.service.ts

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { BottomSheetOptions as MaterialBottomSheetOptions } from '@nativesc
33
import { AppHostView, DetachedLoader, once } from '@nativescript/angular';
44
import { LayoutBase, ProxyViewContainer, View } from '@nativescript/core';
55
import { Observable, Subject } from 'rxjs';
6-
import { filter, first, map } from 'rxjs/operators';
76

87
export type BaseShowBottomSheetOptions = Omit<MaterialBottomSheetOptions, 'closeCallback' | 'view'>;
98

@@ -17,35 +16,36 @@ export class BottomSheetParams {
1716

1817
type ViewWithDialogRoot = View & { _ngDialogRoot?: View };
1918

19+
interface SheetRef<TResult = unknown> {
20+
detachedLoader?: ComponentRef<DetachedLoader>;
21+
componentView?: View;
22+
result: Subject<TResult>;
23+
}
24+
2025
@Injectable({
2126
providedIn: 'root'
2227
})
2328
export class BottomSheetService {
24-
private readonly results$ = new Subject<{ sheetId: number; result: any }>();
25-
26-
private detachedLoader: ComponentRef<DetachedLoader>;
27-
28-
private componentView: View;
29-
30-
private nextSheetId = 0;
31-
32-
public show<T = any>(type: Type<any>, options: BottomSheetOptions): Observable<T> {
29+
public show<TResult = any>(type: Type<any>, options: BottomSheetOptions): Observable<TResult> {
3330
return this.showWithCloseCallback(type, options).observable;
3431
}
3532

36-
public showWithCloseCallback<T = any>(type: Type<any>, options: BottomSheetOptions): { observable: Observable<T>; closeCallback: () => void } {
33+
public showWithCloseCallback<TResult = any>(type: Type<any>, options: BottomSheetOptions): { observable: Observable<TResult>; closeCallback: () => void } {
3734
if (!options.viewContainerRef) {
3835
throw new Error('No viewContainerRef: Make sure you pass viewContainerRef in BottomSheetOptions.');
3936
}
4037

41-
const sheetId = this.nextSheetId++;
38+
const sheetRef: SheetRef<TResult> = {
39+
result: new Subject()
40+
};
41+
4242
const parentView = this.getParentView(options.viewContainerRef);
4343
const factoryResolver = this.getFactoryResolver(options.viewContainerRef);
44-
const bottomSheetParams = this.getBottomSheetParams(options.context, sheetId);
44+
const bottomSheetParams = this.getBottomSheetParams(options.context, sheetRef);
4545

46-
this.detachedLoader = this.createDetachedLoader(factoryResolver, bottomSheetParams, options.viewContainerRef);
46+
sheetRef.detachedLoader = this.createDetachedLoader(factoryResolver, bottomSheetParams, options.viewContainerRef);
4747

48-
this.loadComponent(type).then((componentView) => {
48+
this.loadComponent(type, sheetRef).then((componentView) => {
4949
parentView.showBottomSheet({
5050
...options,
5151
...bottomSheetParams,
@@ -54,11 +54,7 @@ export class BottomSheetService {
5454
});
5555

5656
return {
57-
observable: this.results$.pipe(
58-
filter((item) => item && item.sheetId === sheetId),
59-
map((item) => item.result),
60-
first()
61-
),
57+
observable: sheetRef.result,
6258
closeCallback: bottomSheetParams.closeCallback
6359
};
6460
}
@@ -98,18 +94,21 @@ export class BottomSheetService {
9894
});
9995
}
10096

101-
private getBottomSheetParams(context: any, sheetId: number): BottomSheetParams {
97+
private getBottomSheetParams(context: any, sheetRef: SheetRef): BottomSheetParams {
10298
const closeCallback = once((args) => {
103-
this.results$.next({ result: args, sheetId });
99+
const { result, componentView, detachedLoader } = sheetRef;
104100

105-
if (!this.componentView) {
106-
return;
107-
}
101+
result.next(args);
102+
result.complete();
108103

109-
this.componentView.closeBottomSheet();
104+
if (componentView) {
105+
componentView.closeBottomSheet();
106+
}
110107

111-
this.detachedLoader.instance.detectChanges();
112-
this.detachedLoader.destroy();
108+
if (detachedLoader) {
109+
detachedLoader.instance.detectChanges();
110+
detachedLoader.destroy();
111+
}
113112
});
114113

115114
return new BottomSheetParams(context, closeCallback);
@@ -122,23 +121,23 @@ export class BottomSheetService {
122121
return viewContainerRef.createComponent(detachedLoaderFactory, 0, childInjector, null);
123122
}
124123

125-
private async loadComponent(type: Type<any>): Promise<View> {
124+
private async loadComponent(type: Type<any>, sheetRef: SheetRef): Promise<View> {
126125
try {
127-
const componentRef = await this.detachedLoader.instance.loadComponent(type);
126+
const componentRef = await sheetRef.detachedLoader.instance.loadComponent(type);
128127
const detachedProxy = componentRef.location.nativeElement as ProxyViewContainer;
129128

130129
if (detachedProxy.getChildrenCount() > 1) {
131130
throw new Error('BottomSheet content has more than one root view.');
132131
}
133132

134-
this.componentView = detachedProxy.getChildAt(0);
133+
sheetRef.componentView = detachedProxy.getChildAt(0);
135134

136-
if (this.componentView.parent instanceof LayoutBase) {
137-
(this.componentView.parent as ViewWithDialogRoot)._ngDialogRoot = this.componentView;
138-
this.componentView.parent.removeChild(this.componentView);
135+
if (sheetRef.componentView.parent instanceof LayoutBase) {
136+
(sheetRef.componentView.parent as ViewWithDialogRoot)._ngDialogRoot = sheetRef.componentView;
137+
sheetRef.componentView.parent.removeChild(sheetRef.componentView);
139138
}
140139

141-
return this.componentView;
140+
return sheetRef.componentView;
142141
} catch (err) {
143142
console.error(err);
144143

0 commit comments

Comments
 (0)