Place Toastr toasts in container in specific component

905 Views Asked by At

Toastr allows you to globally define container, where toasts are displayed in this way:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { ToastrModule, ToastContainerModule } from 'ngx-toastr';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,

    ToastrModule.forRoot({ positionClass: 'inline' }), // <-- this
    ToastContainerModule,                              // <-- lines
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

I want to achieve something similar, I want to place these toasts in a specific container but only within one component, so that it doesn't affect the rest of the toasts in the rest of the application. This is a pure component, no module or route.

Is something like this even possible?

2

There are 2 best solutions below

0
On

What we did is to define a custom container on AppComponent in order to re-use it as needed from other components.

So first you define a custom container in the template (pretty much like how it is explained in the docs). Beware that currently (2023-11-14) the docs are a bit outdated, instead of importing ToastContainerModule you now have to import ToastContainerDirective (which is now standalone) in either a standalone component or in the corresponding module (in our case in AppModule):

So in AppModule we have:

  imports: [
    BrowserAnimationsModule,
    // ...    
    ToastrModule.forRoot(),
    ToastContainerDirective
  ],

And on the app.component.html template:

<!-- custom toastr container -->
<div toastContainer aria-live="polite"></div>
<router-outlet> ... </router-outlet>

The big difference to the docs, is that we don't add { positionClass: 'inline' } as a "global" option on the module-import, but instead define different components and options for different use cases and leave the default as an overlay.

Because we wanted to re-use the custom-inline container (and several others) in any component, we do all the configuration in a service e.g. CustomToastrService. Also, if you want to change the layout(s) you'll need custom component(s).

In the service you can define methods for different combinations of options/custom components, depending on your needs:

export type ToastOptions = {msg: string; type: 'error'|'success'|...; title?: string; ...};

@Injectable({providedIn:'root'})
export class CustomToastrService {
  constructor(private toastrService: ToastrService) { 
    //... 
  }

  /* Show a toastr inline */
  public showInlineToastr(options: ToastOptions) {
    const toastOptions = {
      toastClass: `ngx-toastr toast-${options.type}`,
      positionClass: 'inline',
      // ... more options
    };
    this.toastrService.show(options.msg, options.title, toastOptions);
  }

  /* Show a toast as an overlay on the top and full-width */
  public showToast(options: ToastOptions) {
    const toastOptions = {
      toastClass: `ngx-toastr toast-${options.type}`,
      positionClass: 'toast-top-full-width',
      // ... more options
    };
    this.toastrService.show(options.msg, options.title, toastOptions);
  }

  // Use a custom component
  public showCustomToast(options: ToastOptions) {
    const toastOptions = {
      toastClass: '', // we set this in the template
      toastComponent: CustomToastComponent,
      // ...
    };
    this.toastrService.show(options.msg, options.title, toastOptions);
  }    
}
3
On

You can apply configurations while triggering a toastr. Check the code below.

this.toastr.success('Textt', 'Text2', {
  positionClass: 'top-right',
});