Skip to content

Commit 66ea80e

Browse files
authored
Merge pull request #253 from toverux/fix/angular-multi-modals
fix(bottomsheet): support multiple modal instances in the Angular service
2 parents 3db3c7b + 169a388 commit 66ea80e

File tree

1 file changed

+49
-49
lines changed

1 file changed

+49
-49
lines changed

src/bottomsheet/angular/bottomsheet.service.ts

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,51 @@
11
import { ComponentFactoryResolver, ComponentRef, Injectable, Injector, Type, ViewContainerRef } from '@angular/core';
2+
import type { BottomSheetOptions as MaterialBottomSheetOptions } from '@nativescript-community/ui-material-bottomsheet';
23
import { AppHostView, DetachedLoader, once } from '@nativescript/angular';
3-
import { ProxyViewContainer } from '@nativescript/core';
4+
import { LayoutBase, ProxyViewContainer, View } from '@nativescript/core';
45
import { Observable, Subject } from 'rxjs';
5-
import { filter, first, map } from 'rxjs/operators';
6-
import { BottomSheetOptions as MaterialBottomSheetOptions } from '@nativescript-community/ui-material-bottomsheet'; // ViewWithBottomSheetBase
76

8-
export type BaseShowBottomSheetOptions = Pick<MaterialBottomSheetOptions, Exclude<keyof MaterialBottomSheetOptions, 'closeCallback' | 'view'>>;
7+
export type BaseShowBottomSheetOptions = Omit<MaterialBottomSheetOptions, 'closeCallback' | 'view'>;
98

109
export interface BottomSheetOptions extends BaseShowBottomSheetOptions {
1110
viewContainerRef?: ViewContainerRef;
1211
}
1312

1413
export class BottomSheetParams {
15-
context: any;
16-
closeCallback: (...args) => void;
14+
public constructor(public readonly context: any, public readonly closeCallback: (...args) => void) {}
15+
}
1716

18-
constructor(context, closeCallback) {
19-
this.context = context;
20-
this.closeCallback = closeCallback;
21-
}
17+
type ViewWithDialogRoot = View & { _ngDialogRoot?: View };
18+
19+
interface SheetRef<TResult = unknown> {
20+
detachedLoader?: ComponentRef<DetachedLoader>;
21+
componentView?: View;
22+
result: Subject<TResult>;
2223
}
2324

2425
@Injectable({
2526
providedIn: 'root'
2627
})
2728
export class BottomSheetService {
28-
private detachedLoader: ComponentRef<DetachedLoader>;
29-
private componentView: any;//ViewWithBottomSheetBase;
30-
private subject$: Subject<{ requestId: number; result: any }> = new Subject();
31-
private currentId = 0;
32-
33-
show<T = any>(type: Type<any>, options: BottomSheetOptions): Observable<T> {
29+
public show<TResult = any>(type: Type<any>, options: BottomSheetOptions): Observable<TResult> {
3430
return this.showWithCloseCallback(type, options).observable;
3531
}
3632

37-
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 } {
3834
if (!options.viewContainerRef) {
3935
throw new Error('No viewContainerRef: Make sure you pass viewContainerRef in BottomSheetOptions.');
4036
}
41-
this.currentId++;
42-
const requestId = this.currentId;
37+
38+
const sheetRef: SheetRef<TResult> = {
39+
result: new Subject()
40+
};
41+
4342
const parentView = this.getParentView(options.viewContainerRef);
4443
const factoryResolver = this.getFactoryResolver(options.viewContainerRef);
45-
const bottomSheetParams = this.getBottomSheetParams(options.context, requestId);
44+
const bottomSheetParams = this.getBottomSheetParams(options.context, sheetRef);
4645

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

49-
this.loadComponent(type).then(componentView => {
48+
this.loadComponent(type, sheetRef).then((componentView) => {
5049
parentView.showBottomSheet({
5150
...options,
5251
...bottomSheetParams,
@@ -55,17 +54,13 @@ export class BottomSheetService {
5554
});
5655

5756
return {
58-
observable: this.subject$.pipe(
59-
filter(item => item && item.requestId === requestId),
60-
map(item => item.result),
61-
first()
62-
),
57+
observable: sheetRef.result,
6358
closeCallback: bottomSheetParams.closeCallback
6459
};
6560
}
6661

67-
private getParentView(viewContainerRef: ViewContainerRef): any {//ViewWithBottomSheetBase {
68-
let parentView = viewContainerRef.element.nativeElement;
62+
private getParentView(viewContainerRef: ViewContainerRef): View {
63+
let parentView = viewContainerRef.element.nativeElement as View;
6964

7065
if (parentView instanceof AppHostView && parentView.ngAppRoot) {
7166
parentView = parentView.ngAppRoot;
@@ -74,8 +69,8 @@ export class BottomSheetService {
7469
// _ngDialogRoot is the first child of the previously detached proxy.
7570
// It should have 'viewController' (iOS) or '_dialogFragment' (Android) available for
7671
// presenting future bottomSheets views.
77-
if (parentView._ngDialogRoot) {
78-
parentView = parentView._ngDialogRoot;
72+
if ((parentView as ViewWithDialogRoot)._ngDialogRoot) {
73+
parentView = (parentView as ViewWithDialogRoot)._ngDialogRoot;
7974
}
8075

8176
return parentView;
@@ -87,7 +82,7 @@ export class BottomSheetService {
8782
return componentContainer.injector.get(ComponentFactoryResolver);
8883
}
8984

90-
private createChildInjector(bottomSheetParams: BottomSheetParams, containerRef: ViewContainerRef) {
85+
private createChildInjector(bottomSheetParams: BottomSheetParams, containerRef: ViewContainerRef): Injector {
9186
return Injector.create({
9287
providers: [
9388
{
@@ -99,17 +94,21 @@ export class BottomSheetService {
9994
});
10095
}
10196

102-
private getBottomSheetParams(context: any, requestId: number) {
103-
const closeCallback = once(args => {
104-
this.subject$.next({ result: args, requestId });
97+
private getBottomSheetParams(context: any, sheetRef: SheetRef): BottomSheetParams {
98+
const closeCallback = once((args) => {
99+
const { result, componentView, detachedLoader } = sheetRef;
100+
101+
result.next(args);
102+
result.complete();
105103

106-
if (!this.componentView) {
107-
return;
104+
if (componentView) {
105+
componentView.closeBottomSheet();
108106
}
109107

110-
this.componentView.closeBottomSheet();
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,25 +121,26 @@ export class BottomSheetService {
122121
return viewContainerRef.createComponent(detachedLoaderFactory, 0, childInjector, null);
123122
}
124123

125-
private async loadComponent(type: Type<any>): Promise<any> {//ViewWithBottomSheetBase> {
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) as any;//ViewWithBottomSheetBase;
133+
sheetRef.componentView = detachedProxy.getChildAt(0);
135134

136-
if (this.componentView.parent) {
137-
(this.componentView.parent)._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;
142-
} catch (e) {
143-
console.error(e);
140+
return sheetRef.componentView;
141+
} catch (err) {
142+
console.error(err);
143+
144144
return null;
145145
}
146146
}

0 commit comments

Comments
 (0)