Przeglądaj źródła

fix(admin-ui): Eliminate race conditions from overlay services

Michael Bromley 7 lat temu
rodzic
commit
ca7f05625d

+ 8 - 9
admin-ui/src/app/core/providers/notification/notification.service.ts

@@ -21,18 +21,16 @@ const TOAST_DURATION = 3000;
  */
 @Injectable()
 export class NotificationService {
-    private hostView: ViewContainerRef;
+    private get hostView(): Promise<ViewContainerRef> {
+        return this.overlayHostService.getHostView();
+    }
     private openToastRefs: Array<{ ref: ComponentRef<NotificationComponent>; timerId: any }> = [];
 
     constructor(
         private i18nService: I18nService,
         private resolver: ComponentFactoryResolver,
-        overlayHostService: OverlayHostService,
-    ) {
-        overlayHostService.getHostView().then(view => {
-            this.hostView = view;
-        });
-    }
+        private overlayHostService: OverlayHostService,
+    ) {}
 
     /**
      * Display a success toast notification
@@ -89,9 +87,10 @@ export class NotificationService {
     /**
      * Load a ToastComponent into the DOM host location.
      */
-    private createToast(config: ToastConfig): void {
+    private async createToast(config: ToastConfig): Promise<void> {
         const toastFactory = this.resolver.resolveComponentFactory(NotificationComponent);
-        const ref = this.hostView.createComponent<NotificationComponent>(toastFactory);
+        const hostView = await this.hostView;
+        const ref = hostView.createComponent<NotificationComponent>(toastFactory);
         const toast: NotificationComponent = ref.instance;
         const dismissFn = this.createDismissFunction(ref);
         toast.type = config.type || 'info';

+ 20 - 20
admin-ui/src/app/shared/providers/modal/modal.service.ts

@@ -1,6 +1,7 @@
 import { ComponentFactoryResolver, Injectable, ViewContainerRef } from '@angular/core';
 import { Type } from '@angular/core/src/type';
-import { Observable, of } from 'rxjs';
+import { from, Observable, of } from 'rxjs';
+import { map, mergeMap } from 'rxjs/operators';
 
 import { OverlayHostService } from '../../../core/providers/overlay-host/overlay-host.service';
 import { ModalDialogComponent } from '../../components/modal-dialog/modal-dialog.component';
@@ -41,16 +42,10 @@ export interface ModalOptions<T> {
  */
 @Injectable()
 export class ModalService {
-    hostView: ViewContainerRef;
-
     constructor(
         private componentFactoryResolver: ComponentFactoryResolver,
-        overlayHostService: OverlayHostService,
-    ) {
-        overlayHostService.getHostView().then(view => {
-            this.hostView = view;
-        });
-    }
+        private overlayHostService: OverlayHostService,
+    ) {}
 
     /**
      * Create a modal from a component. The component must implement the {@link Dialog} interface.
@@ -96,17 +91,22 @@ export class ModalService {
         options?: ModalOptions<T>,
     ): Observable<R | undefined> {
         const modalFactory = this.componentFactoryResolver.resolveComponentFactory(ModalDialogComponent);
-        const modalComponentRef = this.hostView.createComponent(modalFactory);
-        const modalInstance: ModalDialogComponent<any> = modalComponentRef.instance;
-        modalInstance.childComponentType = component;
-        modalInstance.options = options;
 
-        return new Observable(subscriber => {
-            modalInstance.closeModal = (result: any) => {
-                modalComponentRef.destroy();
-                subscriber.next(result);
-                subscriber.complete();
-            };
-        });
+        return from(this.overlayHostService.getHostView()).pipe(
+            mergeMap(hostView => {
+                const modalComponentRef = hostView.createComponent(modalFactory);
+                const modalInstance: ModalDialogComponent<any> = modalComponentRef.instance;
+                modalInstance.childComponentType = component;
+                modalInstance.options = options;
+
+                return new Observable(subscriber => {
+                    modalInstance.closeModal = (result: any) => {
+                        modalComponentRef.destroy();
+                        subscriber.next(result);
+                        subscriber.complete();
+                    };
+                });
+            }),
+        );
     }
 }