From f57e4c646f638dc06ff1c79558ea560e41e415bc Mon Sep 17 00:00:00 2001 From: "Maxime F." Date: Mon, 3 Mar 2025 11:08:41 +0100 Subject: [PATCH] feat(NgxStatusService): add support for subtitle + fix "component already have attached view" error --- projects/status/src/status.service.ts | 43 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/projects/status/src/status.service.ts b/projects/status/src/status.service.ts index 995fdb19..b51fee00 100644 --- a/projects/status/src/status.service.ts +++ b/projects/status/src/status.service.ts @@ -1,5 +1,5 @@ import { DOCUMENT } from '@angular/common'; -import { ApplicationRef, DestroyRef, EmbeddedViewRef, inject, Injectable, Injector, ViewContainerRef } from '@angular/core'; +import { ApplicationRef, DestroyRef, EmbeddedViewRef, EventEmitter, inject, Injectable, Injector, ViewContainerRef } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { from, mergeWith, switchMap, take, tap, timer } from 'rxjs'; @@ -28,29 +28,37 @@ export class NgxStatusService { /** * Display an information message to the screen. */ - public info(text: string, title = '', duration?: number, actions?: readonly NgxStatusAction[]): void { - this.showStatus({ type: 'info', title, text, duration, actions }); + public info(text: string, title: string | { title: string; subtitle: string } = '', duration?: number, actions?: readonly NgxStatusAction[]): void { + const { title: mainTitle, subtitle = '' } = typeof title === 'string' ? { title } : title; + + this.showStatus({ type: 'info', title: mainTitle, subtitle, text, duration, actions }); } /** * Display an information message to the screen. */ - public success(text: string, title = '', duration?: number, actions?: readonly NgxStatusAction[]): void { - this.showStatus({ type: 'success', title, text, duration, actions }); + public success(text: string, title: string | { title: string; subtitle: string } = '', duration?: number, actions?: readonly NgxStatusAction[]): void { + const { title: mainTitle, subtitle = '' } = typeof title === 'string' ? { title } : title; + + this.showStatus({ type: 'success', title: mainTitle, subtitle, text, duration, actions }); } /** * Display a warning message to the screen. */ - public warning(text: string, title = 'Attention', technicalText?: string, duration?: number, actions?: readonly NgxStatusAction[]): void { - this.showStatus({ type: 'warn', title, text, duration, technicalText, actions }); + public warning(text: string, title: string | { title: string; subtitle: string } = 'Attention', technicalText?: string, duration?: number, actions?: readonly NgxStatusAction[]): void { + const { title: mainTitle, subtitle = '' } = typeof title === 'string' ? { title } : title; + + this.showStatus({ type: 'warn', title: mainTitle, subtitle, text, duration, technicalText, actions }); } /** * Display an error message to the screen and send it to HugLog. */ - public error(text: string, title = 'Erreur', technicalText?: string, duration?: number, actions?: readonly NgxStatusAction[]): void { - this.showStatus({ type: 'danger', title, text, duration, technicalText, actions }); + public error(text: string, title: string | { title: string; subtitle: string } = 'Erreur', technicalText?: string, duration?: number, actions?: readonly NgxStatusAction[]): void { + const { title: mainTitle, subtitle = '' } = typeof title === 'string' ? { title } : title; + + this.showStatus({ type: 'danger', title: mainTitle, subtitle, text, duration, technicalText, actions }); } public showStatus(status: NgxStatus): void { @@ -59,22 +67,23 @@ export class NgxStatusService { switchMap(component => { // Get the root view container ref of the application by injecting it into the root component const applicationRef = this.injector.get(ApplicationRef); - const rootViewContainerRef = applicationRef.components[0].injector.get(ViewContainerRef); + const rootViewContainerRef = applicationRef.components[0]?.injector.get(ViewContainerRef); // Insert the modal component into the root view container - const componentRef = rootViewContainerRef.createComponent(component.NgxStatusComponent); - componentRef.instance.status = status; - applicationRef.attachView(componentRef.hostView); + const componentRef = rootViewContainerRef?.createComponent(component.NgxStatusComponent); - const domElement = (componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement; - this.document.body.appendChild(domElement); + if (componentRef) { + componentRef.instance.status = status; + const domElement = (componentRef?.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement; + this.document.body.appendChild(domElement); + } applicationRef.tick(); const duration = status.duration || (status.type === 'danger' && durationLong) || durationShort; return timer(duration).pipe( - mergeWith(componentRef.instance.close), + mergeWith(componentRef?.instance.close ?? new EventEmitter), tap(() => { - componentRef.destroy(); + componentRef?.destroy(); applicationRef.tick(); }) );