Home > Blockchain >  PrimeNG avoid overlap on toasts with different keys in same position
PrimeNG avoid overlap on toasts with different keys in same position

Time:01-13

below is a sample of my html:

<p-toast key="key1" position="bottom-right" [preventOpenDuplicates]="true"></p-toast>
<p-toast key="key2" position="bottom-right" [preventOpenDuplicates]="true"></p-toast>

Each toast refers to a certain type of system notification so it could be possible to selectively clear just one as well as all notifications.

But in my component, if I trigger all above keys by below commands:

this.messageService.add({key: 'key1',severity: 'error',summary: 'Notification',detail: 'Detail Err',life: 2000,sticky: true});
this.messageService.add({key: 'key2',severity: 'warn',summary: 'Notification',detail: 'Detail Warning !!!',life: 2000,sticky: true});

The result will be consist in two toasts overlapped:

enter image description here

Finally here we go to the main question: is it possible to stack above toasts just like if they had some key, same behaviour of a toast html tag without the key as below:

enter image description here

of course preserving the capability to selectively close the desired toast.

Fiddle here

Thanks in advance

CodePudding user response:

Yes, you can, but not with this approach, so read to the end.

The first issue about the overlapping of different toast components, in my opinion, is not achievable, as they are independent components and have no idea what is going on with any other instances of the toast component.

So given the first statement, we have to put all toast in a single toast cmp instance (e.g. t be using the same key)

Here comes the second problem, about the differential clearing of the toasts, as seen in the primeNg docs, the library provides an option to either clear all tooltips, or all tooltips in certain tooltip components (based on key). Which is not the desired result. For more info on what clearing is supported, you can check the docs toast docs here.

And now time for the workaround.

If we go here primeNG toast source we can see that all messages (e.g. visible toasts) are stored in a component called Toast in the variable messages. So my approach for clearing specific messages, will be to take the Toast component with ViewChild and fiddle with them like so:

export class AppComponent {
   @ViewChild(Toast) toast: Toast;

  clear(type: string) {
    this.toast.messages = this.toast.messages.filter(
      (x) => x.severity !== type
    );
  }
}

So whenever I hit some clear notification of type button I will clear all instances of that message from the toast.

All should work now, but in reality, all third party component libraries usually use the OnPush change detection strategy, so we have to take one extra action. We have to trigger the change detection of the Toast and will end up with the following solution

export class AppComponent {
  @ViewChild(Toast) toast: Toast;
  @ViewChild(Toast, { read: ViewContainerRef, static: true })
 ...
 clear(type: string) {
    this.toast.messages = this.toast.messages.filter(
      (x) => x.severity !== type
    );
    const changeDetectorRef = this.toastRef.injector.get(ChangeDetectorRef);
    changeDetectorRef.detectChanges();
  }
}

For more info about CDR and the techniques used here, you can check the following article : Forcing change detection on third-party Angular components

Working stackblitz

Notes: Probably there will be some funny stuff with the close events emitted from the Toast component, but I belive that they won't cause any issues.

  • Related