diff --git a/ui-ngx/src/app/shared/components/snack-bar-component.html b/ui-ngx/src/app/shared/components/snack-bar-component.html
index 53f23fcf8a..573166fd1e 100644
--- a/ui-ngx/src/app/shared/components/snack-bar-component.html
+++ b/ui-ngx/src/app/shared/components/snack-bar-component.html
@@ -25,5 +25,5 @@
'info-toast': notification.type === 'info'
}">
-
+
diff --git a/ui-ngx/src/app/shared/components/snack-bar-component.scss b/ui-ngx/src/app/shared/components/snack-bar-component.scss
index 6ef4191efb..8b211bffce 100644
--- a/ui-ngx/src/app/shared/components/snack-bar-component.scss
+++ b/ui-ngx/src/app/shared/components/snack-bar-component.scss
@@ -16,6 +16,33 @@
:host {
display: inline-block;
pointer-events: all;
+ &.toast-panel {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ display: flex;
+ &.left {
+ justify-content: flex-start;
+ }
+ &.right {
+ justify-content: flex-end;
+ }
+ &.top {
+ align-items: flex-start;
+ }
+ &.bottom {
+ align-items: flex-end;
+ }
+ &.h-center {
+ justify-content: center;
+ }
+ &.v-center {
+ align-items: center;
+ }
+ }
.tb-toast {
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
color: #fff;
diff --git a/ui-ngx/src/app/shared/components/toast.directive.ts b/ui-ngx/src/app/shared/components/toast.directive.ts
index 1d59b86a54..fb704c74db 100644
--- a/ui-ngx/src/app/shared/components/toast.directive.ts
+++ b/ui-ngx/src/app/shared/components/toast.directive.ts
@@ -16,9 +16,9 @@
import {
AfterViewInit, ChangeDetectorRef,
- Component, ComponentRef,
+ Component, ComponentFactoryResolver, ComponentRef,
Directive,
- ElementRef,
+ ElementRef, HostBinding,
Inject,
Input,
NgZone,
@@ -34,8 +34,7 @@ import { BreakpointObserver } from '@angular/cdk/layout';
import { MediaBreakpoints } from '@shared/models/constants';
import { MatButton } from '@angular/material/button';
import Timeout = NodeJS.Timeout;
-import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
-import { ComponentPortal, PortalInjector } from '@angular/cdk/portal';
+import { PortalInjector } from '@angular/cdk/portal';
@Directive({
selector: '[tb-toast]'
@@ -49,7 +48,6 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
private hideNotificationSubscription: Subscription = null;
private snackBarRef: MatSnackBarRef = null;
- private overlayRef: OverlayRef;
private toastComponentRef: ComponentRef;
private currentMessage: NotificationMessage = null;
@@ -58,7 +56,7 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
constructor(private elementRef: ElementRef,
private viewContainerRef: ViewContainerRef,
private notificationService: NotificationService,
- private overlay: Overlay,
+ private componentFactoryResolver: ComponentFactoryResolver,
private snackBar: MatSnackBar,
private ngZone: NgZone,
private breakpointObserver: BreakpointObserver,
@@ -104,9 +102,11 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
if (this.snackBarRef) {
this.snackBarRef.dismiss();
}
-
- const position = this.overlay.position();
- let panelClass = ['tb-toast-panel'];
+ if (this.toastComponentRef) {
+ this.viewContainerRef.detach(0);
+ this.toastComponentRef.destroy();
+ }
+ let panelClass = ['tb-toast-panel', 'toast-panel'];
if (notificationMessage.panelClass) {
if (typeof notificationMessage.panelClass === 'string') {
panelClass.push(notificationMessage.panelClass);
@@ -114,46 +114,35 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
panelClass = panelClass.concat(notificationMessage.panelClass);
}
}
- const overlayConfig = new OverlayConfig({
- panelClass,
- backdropClass: 'cdk-overlay-transparent-backdrop',
- hasBackdrop: false,
- disposeOnNavigation: true
- });
- let originX;
- let originY;
const horizontalPosition = notificationMessage.horizontalPosition || 'left';
const verticalPosition = notificationMessage.verticalPosition || 'top';
if (horizontalPosition === 'start' || horizontalPosition === 'left') {
- originX = 'start';
+ panelClass.push('left');
} else if (horizontalPosition === 'end' || horizontalPosition === 'right') {
- originX = 'end';
+ panelClass.push('right');
} else {
- originX = 'center';
+ panelClass.push('h-center');
}
if (verticalPosition === 'top') {
- originY = 'top';
+ panelClass.push('top');
} else {
- originY = 'bottom';
+ panelClass.push('bottom');
}
- const connectedPosition: ConnectedPosition = {
- originX,
- originY,
- overlayX: originX,
- overlayY: originY
- };
- overlayConfig.positionStrategy = position.flexibleConnectedTo(this.elementRef)
- .withPositions([connectedPosition]);
- this.overlayRef = this.overlay.create(overlayConfig);
+
+ const componentFactory = this.componentFactoryResolver.resolveComponentFactory(TbSnackBarComponent);
const data: ToastPanelData = {
- notification: notificationMessage
+ notification: notificationMessage,
+ panelClass,
+ destroyToastComponent: () => {
+ this.viewContainerRef.detach(0);
+ this.toastComponentRef.destroy();
+ }
};
const injectionTokens = new WeakMap([
- [MAT_SNACK_BAR_DATA, data],
- [OverlayRef, this.overlayRef]
+ [MAT_SNACK_BAR_DATA, data]
]);
const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens);
- this.toastComponentRef = this.overlayRef.attach(new ComponentPortal(TbSnackBarComponent, this.viewContainerRef, injector));
+ this.toastComponentRef = this.viewContainerRef.createComponent(componentFactory, 0, injector);
this.cd.detectChanges();
if (notificationMessage.duration && notificationMessage.duration > 0) {
@@ -173,7 +162,6 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
clearTimeout(this.dismissTimeout);
this.dismissTimeout = null;
}
- this.overlayRef = null;
this.toastComponentRef = null;
this.currentMessage = null;
});
@@ -181,43 +169,45 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
}
private showSnackBar(notificationMessage: NotificationMessage, isGtSm: boolean) {
- const data: ToastPanelData = {
- notification: notificationMessage,
- parent: this.elementRef
- };
- const config: MatSnackBarConfig = {
- horizontalPosition: notificationMessage.horizontalPosition || 'left',
- verticalPosition: !isGtSm ? 'bottom' : (notificationMessage.verticalPosition || 'top'),
- viewContainerRef: this.viewContainerRef,
- duration: notificationMessage.duration,
- panelClass: notificationMessage.panelClass,
- data
- };
this.ngZone.run(() => {
if (this.snackBarRef) {
this.snackBarRef.dismiss();
}
+ const data: ToastPanelData = {
+ notification: notificationMessage,
+ parent: this.elementRef,
+ panelClass: [],
+ destroyToastComponent: () => {}
+ };
+ const config: MatSnackBarConfig = {
+ horizontalPosition: notificationMessage.horizontalPosition || 'left',
+ verticalPosition: !isGtSm ? 'bottom' : (notificationMessage.verticalPosition || 'top'),
+ viewContainerRef: this.viewContainerRef,
+ duration: notificationMessage.duration,
+ panelClass: notificationMessage.panelClass,
+ data
+ };
this.snackBarRef = this.snackBar.openFromComponent(TbSnackBarComponent, config);
- });
- if (notificationMessage.duration && notificationMessage.duration > 0 && notificationMessage.forceDismiss) {
- if (this.dismissTimeout !== null) {
- clearTimeout(this.dismissTimeout);
- this.dismissTimeout = null;
- }
- this.dismissTimeout = setTimeout(() => {
- if (this.snackBarRef) {
- this.snackBarRef.instance.actionButton._elementRef.nativeElement.click();
+ if (notificationMessage.duration && notificationMessage.duration > 0 && notificationMessage.forceDismiss) {
+ if (this.dismissTimeout !== null) {
+ clearTimeout(this.dismissTimeout);
+ this.dismissTimeout = null;
}
- this.dismissTimeout = null;
- }, notificationMessage.duration);
- }
- this.snackBarRef.afterDismissed().subscribe(() => {
- if (this.dismissTimeout !== null) {
- clearTimeout(this.dismissTimeout);
- this.dismissTimeout = null;
+ this.dismissTimeout = setTimeout(() => {
+ if (this.snackBarRef) {
+ this.snackBarRef.instance.actionButton._elementRef.nativeElement.click();
+ }
+ this.dismissTimeout = null;
+ }, notificationMessage.duration);
}
- this.snackBarRef = null;
- this.currentMessage = null;
+ this.snackBarRef.afterDismissed().subscribe(() => {
+ if (this.dismissTimeout !== null) {
+ clearTimeout(this.dismissTimeout);
+ this.dismissTimeout = null;
+ }
+ this.snackBarRef = null;
+ this.currentMessage = null;
+ });
});
}
@@ -235,8 +225,9 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
}
ngOnDestroy(): void {
- if (this.overlayRef) {
- this.overlayRef.dispose();
+ if (this.toastComponentRef) {
+ this.viewContainerRef.detach(0);
+ this.toastComponentRef.destroy();
}
if (this.notificationSubscription) {
this.notificationSubscription.unsubscribe();
@@ -250,6 +241,8 @@ export class ToastDirective implements AfterViewInit, OnDestroy {
interface ToastPanelData {
notification: NotificationMessage;
parent?: ElementRef;
+ panelClass: string[];
+ destroyToastComponent: () => void;
}
import {
@@ -288,6 +281,11 @@ export class TbSnackBarComponent implements AfterViewInit, OnDestroy {
@ViewChild('actionButton', {static: true}) actionButton: MatButton;
+ @HostBinding('class')
+ get panelClass(): string[] {
+ return this.data.panelClass;
+ }
+
private parentEl: HTMLElement;
private snackBarContainerEl: HTMLElement;
private parentScrollSubscription: Subscription = null;
@@ -305,9 +303,7 @@ export class TbSnackBarComponent implements AfterViewInit, OnDestroy {
private data: ToastPanelData,
private elementRef: ElementRef,
@Optional()
- private snackBarRef: MatSnackBarRef,
- @Optional()
- private overlayRef: OverlayRef) {
+ private snackBarRef: MatSnackBarRef) {
this.animationState = !!this.snackBarRef ? 'default' : 'opened';
this.notification = data.notification;
}
@@ -319,9 +315,8 @@ export class TbSnackBarComponent implements AfterViewInit, OnDestroy {
this.snackBarContainerEl.style.position = 'absolute';
this.updateContainerRect();
this.updatePosition(this.snackBarRef.containerInstance.snackBarConfig);
- const snackBarComponent = this;
this.parentScrollSubscription = onParentScrollOrWindowResize(this.parentEl).subscribe(() => {
- snackBarComponent.updateContainerRect();
+ this.updateContainerRect();
});
}
}
@@ -373,7 +368,7 @@ export class TbSnackBarComponent implements AfterViewInit, OnDestroy {
const isFadeOut = (toState as ToastAnimationState) === 'closing';
const itFinished = this.animationState === 'closing';
if (isFadeOut && itFinished) {
- this.overlayRef.dispose();
+ this.data.destroyToastComponent();
}
}
}