Search Lessons, Code Snippets, and Videos
search by algolia
X
#native_cta# #native_desc# Sponsored by #native_company#

Angular Toast Message Notifications From Scratch

Episode 20 written by Jeff Delaney
full courses and content on fireship.io

In this lesson, we are going to build toast notifications from scratch with Angular 4. There are a couple of good Angular toast packages that solve this problem, but it’s not very hard to do from scratch.

This implementation provides a feed of 5 messages/notifications, which the user can dismiss by clicking. A service will manage the notifications, so they can be observed or updated from any component.

You could manage notifications completely client side, but I am going to store the toast messages on the backend Firebase database as well. This is useful if you plan on showing the user a notification history, serve users on multiple platforms, or if you need messages to persist between sessions. It also opens the possibility to manage notifications with Cloud Functions in the background.

Frontend Design

In this demo, I am using Bulma on the frontend, but you could easily swap our the CSS with Bootstrap, Material, or your own custom classes.

We will have three different types of messages, success, info, and danger and a close button to dismiss the notifications to remove them from the feed.

toast messages demo with Angular and Firebase

The Toast Service

The ToastService can be injected anywhere in the app to trigger notifications. First, let’s define a new class to conceptualize the message itself.

export class Message {
content: string;
style: string;
dismissed: boolean = false;

constructor(content, style?) {
this.content = content
this.style = style || 'info'
}

}

A Message must be instantiated with a content string, and can also be passed an optional style? argument.

getMessages function will return a FirebaseListObservable, limited to the last 5 messages.

sendMessage can be called anywhere in your app to update the current toast feed.

dismissMessage should be trigged by the user to hide the message.

@Injectable()
export class ToastService {


constructor(private db: AngularFireDatabase) { }

getMessages(): FirebaseListObservable<Message[]> {
return this.db.list('/messages', {
query: {
orderByKey: true,
limitToLast: 5
}
});
}

sendMessage(content, style) {
const message = new Message(content, style)
this.db.list('/messages').push(message)
}

dismissMessage(messageKey) {
this.db.object(`messages/${messageKey}`).update({'dismissed': true})
}

}

Reversing and Filtering the Observable with a Pipe

We need to create a custom pipe that can (1) reverse the order of the messages to show the most recent first and (2) filter out the dismissed messages. Run ng g pipe reverse, then import the filter and reverse functions from Lodash.

import { Pipe, PipeTransform } from '@angular/core';
import { filter, reverse } from 'lodash';

@Pipe({
name: 'reverse'
})
export class ReversePipe implements PipeTransform {

transform(value) {
if (!value) return;

value = filter(value, ['dismissed', false])

return reverse(value)
}

}

Building the Toast Messages Component

The component itself will go directly in the AppComponent, outside the scope of the router, because we want users to see it no matter where they are.

<router-outlet></router-outlet>
<toast-messages></toast-messages>

The component’s template will loop over the observable – notice how we are chaining together the the pipes async | reverse. Then use ngClass to match the message style to Bulma’s notification CSS styles. Lastly, the dismiss function is added on the button click.

<div class="wrapper">
<aside *ngFor="let message of messages | async | reverse">
<div class="notification"

[ngClass]="{'is-info': message.style=='info',
'is-danger': message.style=='danger',
'is-success': message.style=='success'}">

<button class="delete" (click)="dismiss(message.$key)"></button>
{{message.content}}
</div>

</aside>
</div>

In the TypeScript, we just inject the service and set the messages variable.

import { Component, OnInit } from '@angular/core';
import { ToastService } from '../toast.service';

@Component({
selector: 'toast-messages',
templateUrl: './toast-messages.component.html',
styleUrls: ['./toast-messages.component.scss'],
})
export class ToastMessagesComponent implements OnInit {

messages: any;

constructor(private toast: ToastService) { }

ngOnInit() {
this.messages = this.toast.getMessages()
}

dismiss(itemKey) {
this.toast.dismissMessage(itemKey)
}

}

Triggering New Messages from Anywhere

The cool thing about realtime apps is their ability to update the messages from anywhere. Simply inject it into a component, then call toast.sendMessage(content, style) and you’re good to go, for example

infoMessage() {
const message = "I have some useful information for you..."
this.toast.sendMessage(message, 'info')
}

Cloud Function Trigger Possibility

Let’s imagine you have a social media app where users can tag or mention each other. You could build a Firebase Cloud Function Database Trigger that scans each new post for usernames using the onWrite callback. When UserFoo mentions UserBar in a post, you update UserBar’s notification feed in real time with something like “Hey, UserFoo just mentioned you in their latest post, check it out”. Amazing possibilities for user engagement.

That’s it for toast message notifications with Angular 4 and Firebase.