We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. (Last updated on: June 24, 2019).
Unfortunately, activation email could not send to your email. Please try again.
Syncfusion Feedback

How to use Toast as an Angular service

Platform: JavaScript - EJ 2 |
Control: Toast |
Published Date: April 4, 2019 |
Last Revised Date: April 4, 2019

 

You can create the Toast component as an Angular service component. The service is a stateless object that contains public functions and maintains the data throughout the life of an application. These functions can be invoked from any Angular component like Controllers, Directives, and more. 

The service will reduce the code when rendering the same Toast component each time in a different component page. You can create the Toast component as a separate service using ‘@Injectable()’.

The following steps explain how to use the Toast component as a separate Angular service:

Step #1:

Create a separate toast.ts service file using @Injectable and provide a service name as ‘ToastService’.  Toast component provides the following methods to define the Angular service:

createToast è creates and returns the toast component. 

showToast/hideToast è shows or hides the toast component using show/hide public method. 

hideToastAll è hides all the Toast components. 

You can access these methods within the angular application when required.

toast.ts

import { Injectable } from '@angular/core';
import { Toast, ToastModel } from '@syncfusion/ej2-notifications';  // Import the toast component
 
@Injectable()
 
export class ToastService {
  public toastInstance: Toast;
  constructor() {}
  
  // To create the toast component
  createToast: Function = (element: HTMLElement, model: ToastModel): Toast => {
    if (!element.classList.contains('e-toast')) {
      this.toastInstance = new Toast(model, element);
    }
    return this.toastInstance
  };
 
  // To show the toast component
  showToast: Function = (elemnet: HTMLElement, model: ToastModel) => {
    this.toastInstance = this.createToast(elemnet, model);
    this.toastInstance.show();
  }
 
  // To hide the toast component
  hideToast: Function = () => {
    if (this.toastInstance) {
      this.toastInstance.hide();
    }
  }
 
  // To hide the all toast component
  hideToastAll: Function = () => {
    if (this.toastInstance) {
      this.toastInstance.hide('All');
    }
  }
}
 

 

Step #2:

You can inject the service using one of the following options:

Option #1: Global service

You can inject the service into a root module by specifying providers into @NgModule.

app.module.ts

 
import { ToastService } from './toast.service/toast';
 
@NgModule({
  providers: [ToastService]
})
 

 

Option #2: Local service

You can inject the service into a component directly by specifying providers into @Component.

app.component.ts

 
import { ToastService } from './toast.service/toast';
 
@Component({
  providers: [ToastService]
})
 

 

Step #3:

You can call the showToast method by clicking the show toast button and the hideToast method is called by clicking the hide toast button using Toast service.  You can use the Toast services in the component by the following ways:  

app.component.ts

import { Component, ElementRef, ViewChild } from '@angular/core';
import { ToastService, showToast } from './toast.service/toast';
 
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @ViewChild("toast") toast: ElementRef;
  constructor(private toastService: ToastService) {
  }
 
  showBtnClick(e) {
    this.toastService.showToast(this.toast.nativeElement, {
      title: 'Toast Sample Header',
      content: 'Toast Content'
    });
  }
 
  hideBtnClick(e) {
    this.toastService.hideToast();;
  }
}
 

 

app.component.html

<div style="text-align:center">
  <h1>
    Syncfusion Toast Service
  </h1>
 
  <button class="e-btn" (click)="this.showBtnClick($event)">Show-toast</button>
    <button class="e-btn" (click)="this.hideBtnClick($event)">Hide-Toast</button>
 
  <div id="ej2Toast" #toast></div>
</div>
 

 

Find the Toast component as an Angular service in this sample.

The following screenshot shows the result of the previous code sample.

 

 

 

ADD COMMENT
You must log in to leave a comment
Comments
Viswadeep
Jun 27, 2019

How would I add the position to Top Right as toast placement?

Reply
Ashokkumar Balasubramanian [Syncfusion]
Jun 28, 2019

Hi Viswadeep,

You can customize the toast position as per your wish using Position property. You can set the ‘Right’ value to ‘X’ position and ‘Top’ value to ‘Y’ position.

Please find the below demo sample.

Demo Sample: https://ej2.syncfusion.com/angular/demos/#/material/toast/positions

User Guide Documentation link:

https://ej2.syncfusion.com/angular/documentation/toast/position/

Sample:

https://stackblitz.com/edit/toast-as-a-anguar-service-3j3p9g?file=src/app/app.component.ts

Please let us know, if you have any concern on this.

Regards, Ashok

Selvamani, Thanigaivelan (T.)
Feb 06, 2020

I have a toast with two buttons OK and Cancel. How to return values based on button click to the calling method?

Reply
Indrajith Srinivasan [Syncfusion]
Feb 10, 2020

Hi SelvaMani,

Greetings from Syncfusion support,

We have validated your reported query, you can return the values based on the click action performed in the toast. Have prepared a sample that returns which button is clicked in the toast.

Sample: https://stackblitz.com/edit/angular-nvf4zk-ne9ky4?file=package.json

Can you please try out the above solution and let us know if it meets your requirement.

Regards, Indrajith

Balazs Hideghety
Jun 09, 2020

The ToastService has a design flaw, as it requires you to pass the HTMLElement to each call. This is not how you want to interact with a service from whithin angular!

Reply
Indrajith Srinivasan [Syncfusion]
Jun 10, 2020

Hi Balazs,

Greetings from Syncfusion support,

We have validated your reported query. The Toast element is passed for each call since the new ToastObj is created every time with the Show-toast button click. So that the defined toast properties can be applied to the corresponding toast element.

Regards, Indrajith

Balazs Hideghety
Jun 29, 2020

Created a custom toast service, which uses a globally configurable container, without the need to pass the HTMLElement into each show method.

And also found another issue, which is a toast Design flaw, concretely:

  • calling toastInstance.hide() does not hides the given instance, but rather the last toast instance inside the container
  • we have to use toastInstance.hide((toastInstance as any).toastEle);
import { Injectable, InjectionToken, Inject, Optional } from '@angular/core';
import { ToastModel, Toast } from '@syncfusion/ej2-angular-notifications';

export const TOAST_SERVICE_TOKEN = new InjectionToken<IAppToastConfig>('TOAST_SERVICE_TOKEN');

export interface IAppToastConfig {
  containerSelector: string;
  defaultModel: ToastModel;
}

/**
 * Will append to first document > div.toast-container!
 */
@Injectable({
  providedIn: 'root'
})
export class AppToastService {

  public defaultModel: ToastModel;
  public defaultElement: HTMLElement;

  constructor(
    @Optional() @Inject(TOAST_SERVICE_TOKEN) private config: IAppToastConfig
  ) {

    this.config = this.config || {} as IAppToastConfig;
    this.config.containerSelector = this.config.containerSelector || "div.toast-container";
    this.config.defaultModel = this.config.defaultModel || {
      showCloseButton: true,
      position: {
        X: 'Right',
        Y: 'Bottom'
      },
      animation: {
        show: { effect: 'ZoomIn', duration: 500, easing: 'ease' },
        hide: { effect: 'ZoomOut', duration: 500, easing: 'ease' }
      },
      showProgressBar: true,
      timeOut: 0,
      extendedTimeout: 0
    } as ToastModel;
  }

  /*
  onShow = new EventEmitter<ToastModel>();
  onClose = new EventEmitter<ToastModel>();
  */

  private createToast(model: ToastModel): Toast {
    const containerElement = document.querySelector(this.config.containerSelector) as HTMLElement;
    const patchedModel = Object.assign({}, this.config.defaultModel, model);
    const toast = new Toast(patchedModel, containerElement);
    return toast;
  }

  //
  // Generic
  //

  public show(model: ToastModel): Toast {
    const toastInstance = this.createToast(model);
    toastInstance.show();
    return toastInstance;
  }

  public hide(toast: Toast) {
      // NOTE:
      // an awful API that syncfusion has, it calls it Toast component/instance, yet:
      // toastInstance.hide() hides not the instance that refers to the element with the given toast, but the last entry inside the container!
      // toastInstance.destroy() seems to destroy the entire container

      // HACK: using internal variable
      toast.hide((toast as any).toastEle);
  }

}
Balazs Hideghety
Jun 29, 2020

Is there a way to: set a custom angular component (with events) as a content (or a template) and have create multiple instance of that given component (without defining it multiple time on the main HTML)?

Reply
Pandiyaraj Muniyandi [Syncfusion]
Jul 01, 2020

Hi Balazs,

Check the below sample for your requirement

https://stackblitz.com/edit/toast-as-a-anguar-service-xbjkrj?file=src/app/toast.service/toast.ts

To close all toast pass 'All' argument in hide method

toastInstance.hide('All');

Regards,

Pandiyaraj

Balazs Hideghety
Jul 02, 2020

Dear @Pandiyaraj Muniyandi

  1. I was not asking on how to close all instances
  2. I mentioned a design flaw related to closing a concrete instance of a toaster (I managed to get it work, see the toaster service I provided, yet the design and suggesting some O-O concepts is not working as an objective-oriented component should)
  3. So now, I'm repeating my question, as I haven't got answer to it: is there an out of the box way to pop-up (create) multiple instance of an angular component (complex, with events) via the syncfusion toaster, if so, how? So the usual approach and sample in the KB is not sufficient, as they are able only to pop-up the one instance defined on the component. So something like this, but i'd like to have multiple (1..N) instances of that alarm toast there: https://ej2.syncfusion.com/angular/demos/#/material/toast/template
Pandiyaraj Muniyandi [Syncfusion]
Jul 03, 2020

Hi Balazs,

We regret this inconvenience caused.

We will check the feasibility and update the further details on before July 8, 2020.

Regards,

Pandiyaraj

Pandiyaraj Muniyandi [Syncfusion]
Jul 08, 2020

Hi Balazs,

Yes you could set angular component as content to Toast by passing selector value as content.

  1. Create
    element using inline style a display: none. unique Id or class should mapped in that element for identification.

// Style display will be dynamically controlled by Toast component

  1. In ToastModel pass id or class selector of target to content property
this.toastService.showToast({

  title: 'Toast Sample Header',

  content: ‘#warning’

});

We have prepared sample for your reference, check the below link

https://stackblitz.com/edit/toast-as-a-anguar-service-w5f2d9?file=src%2Fapp%2Fapp.component.ts

Regards,

Pandiyaraj

Pandiyaraj Muniyandi [Syncfusion]
Jul 08, 2020

Hi Balazs,

Ignore the previous update.

Yes, you could set angular component as content to Toast by passing selector value as content.

  1. Create
    element using inline style a display: none. unique Id or class should be mapped in that element for identification.

// Style display will be dynamically controlled by Toast component

<div id="warning" style="**display: none**">

  Warning content

  // Here we used DropDownList component

  <**ejs-dropdownlist** id='ddlelement' [dataSource]='data' value='Snooker'></**ejs-dropdownlist**>

</div>
  1. list text hereIn ToastModel pass id or class selector of the target to content property

    this.toastService.showToast({

      title: 'Toast Sample Header',

      **content: ‘#warning’**

    });

We have prepared sample for your reference, check the below link

https://stackblitz.com/edit/toast-as-a-anguar-service-w5f2d9?file=src%2Fapp%2Fapp.component.ts

Regards,

Pandiyaraj

Balazs Hideghety
Jul 08, 2020

The provided sample does not work, if you open up multiple instances of the same toaster, then the result will be a non working select inside.

Also the provided sample requires me to have a DOM element instantiated, so it's not a ng-template.

Let's phrase the original request again:

  • provided I have a ng-template defined
  • to which a TemplateRef exists on the TS side
  • how do I programmatically pop up a toast from the TS side, with the angular ng-template (component)
  • without instantiating that ng-template inside the HTML (via ngTemplateOutlet)

The use case:

  • i'd like to have a global toaster service
  • the service has a container on the main app.component
  • a given a different angular component, which decides to pop up a toast message, by providing a ng-template (TemplateRef) - the template is defined on the "different angular component"

How to achieve that?

If I would not have used the syncfusion Toaster component, I'd create the component dynamically (so possibly bypassing even the TemplateRef approach), and would ensure with CSS that it places well - so that it's attached to the container.

Now as we got the syncfusion bundle and the Toast coponent, the question is: how to achieve the same via the component (as it has some additional features beside the "simple" approach I've described).

Pandiyaraj Muniyandi [Syncfusion]
Jul 09, 2020

Hi Balazs,

We have prepared a sample to meet your desired requirement, check the below link

https://stackblitz.com/edit/angular-cqbaco-mjxugy?embed=1&file=app.component.ts

In the above sample, we have covered your following requirements

  • Reusable dynamic toast (With new instance)

  • Pass ng-template (using TemplateRef) as content to Toast (Render custom component into Toast)

  • Programmatically show a Toast from TS

Regards,

Pandiyaraj

Balazs Hideghety
Jul 10, 2020

Thank you, it still fails to open up multiple instances of the same type of toast. Also any specific reason that the ToastInstance was also created dynamically and not in the usual way via ToastModel?

Pandiyaraj Muniyandi [Syncfusion]
Jul 14, 2020

Hi Balazs,

  1. ToastModel approach is not suitable to achieve your requirement.

  2. In previous shared sample, if you pass same template again it won't work. So you need to pass different template to show a toast for multiple instance.

Regards,

Pandiyaraj

Please sign in to access our KB

This page will automatically be redirected to the sign-in page in 10 seconds.

Up arrow icon

Warning Icon You are using an outdated version of Internet Explorer that may not display all features of this and other websites. Upgrade to Internet Explorer 8 or newer for a better experience.Close Icon

Live Chat Icon For mobile
Live Chat Icon