Building Angular Popup. Angular Alert Step-by-Step Guide
In this post we will build together Angular alert or Angular notification on the top of the page without any additional libraries.
But if you just want to use a library and you don't want to implement anything I can highly recommend you to look on ng-bootstrap or angular-material libraries. There you get alert component which is closable, with styling and different configuration but in this post we want to create our own alert so we can fully control how it is working inside.
Architecture of the project
So what is the idea? In different places of our application we want to show our alert. Our alert is always situated at the same place on the top of the page. Which means we must render it in app.component
and not in every single component.
Then we need something sharable which can call this alert and show it. Additionally after several seconds this alert must disappear.
This means that we need 2 different things. First of all we need an AlertComponent
which will just have some trying and markup and secondly a service which will manage this alert.
Let's create first a simple alert component.
// src/app/alert/alert.component.ts
@Component({
selector: 'alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.css'],
standalone: true,
})
export class AlertComponent {}
And let's render just a word Alert
inside our markup.
Now we need to render it on the top of the page in our app.component
.
<!-- app/app.component.html !-->
<h1>Monsterlessons Academy</h1>
<alert></alert>
It order for it to work we must import our standalone AlertComponent
in our AppComponent
.
// src/app/app/app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [RouterOutlet, AlertComponent],
})
export class AppComponent {}
Adding typings
Now in order to understand how our alert works and what we need to pass inside we want to create several types.
// src/app/alert/types/alertType.enum.ts
export enum AlertTypeEnum {
success = 'success',
info = 'info',
warning = 'warning',
danger = 'danger',
}
Here we defined all possible types of our alert. Now let's define an alert itself.
// src/app/alert/types/alert.interface.ts
import { AlertTypeEnum } from './alertType.enum';
export interface AlertInterface {
type: AlertTypeEnum;
text: string;
}
This is our alert which shows that in order to create an alert we must provide type
and text
inside.
Now let's define a an alert inside our component just for testing.
export class AlertComponent {
alert: AlertInterface = {
type: AlertTypeEnum.success,
text: 'This is test alert'
}
}
Adding markup
Now we can write markup for our testing alert.
<div [ngClass]="['alert', alert.type]" *ngIf="alert">{{ alert.text }}</div>
Here we render alert if it is not null (which happens when alert is not there) and apply 2 classes alert
and alert.type
which colors component differently.
But as we used ngClass
and ngIf
inside our markup we must import CommonModule
to our alert component.
@Component({
...
imports: [CommonModule],
})
export class AlertComponent {}
Creating CSS
The only thing that we are missing is CSS for our alert component. Let's add it now.
.alert {
padding: 16px;
border-radius: 6px;
font-size: 16px;
font-weight: 400;
}
.success {
color: #0f5132;
background: #d1e7dd;
}
.info {
color: #055160;
background: #cff4fc;
}
.warning {
color: #664d03;
background: #fff3cd;
}
.danger {
color: #842029;
background: #f8d7da;
}
Here is default styles for alert
that we apply always and different types that we defined previously.
As you can see in browser our testing alert is rendered and it gets correct colors.
Show alert from any place
But we don't want to just render alert always. We want to open it through service and provide different types inside. Let's create a service now.
// src/app/alert/services/alert.services.ts
@Injectable({
providedIn: 'root',
})
export class AlertService {
private alert$ = new Subject<AlertInterface>();
setAlert(alert: AlertInterface): void {
this.alert$.next(alert);
}
getAlert(): Observable<AlertInterface> {
return this.alert$.asObservable();
}
}
We create a Subject
inside our AlertService
so our AlertComponent
can subscribe to it and understand when we want to show an alert. Also it allows us to pass new data to Subject
which we do with setAlert
method. As you can see we must provide an AlertInterface
inside to change it.
We also have a getAlert
method which return for us a Subject
as an Observable
. This is exactly how we will subscribe to changes in our AlertComponent
.
Now let's try to trigger an alert from AppComponent
.
<button (click)="showAlert(alertTypes.danger)">Show danger</button>
<button (click)="showAlert(alertTypes.success)">Show success</button>
Here I added 2 click events to show different types of alerts.
export class AppComponent {
alertTypes = AlertTypeEnum;
constructor(private alertService: AlertService) {}
showAlert(type: AlertTypeEnum) {
this.alertService.setAlert({
type,
text: 'THis is our test alert',
});
}
}
And here is showAlert
function which just calls setAlert
from our service. This is exactly how we trigger our alert from any place.
But we should also make some change in our AlertComponent
so that we render alerts from the service.
export class AlertComponent implements OnInit {
alert?: AlertInterface;
constructor(private alertService: AlertService) {}
ngOnInit(): void {
this.alertService.getAlert().subscribe((alert) => {
this.alert = alert;
});
}
}
Here we subscribed to our service and every time when we get the alert we render it in our markup.
As you can see we are getting real alert and not our testing alert and render it.
Removing alert
But we are still missing a feature with removing our alert after several seconds from the screen.
export class AlertComponent implements OnInit {
alert?: AlertInterface;
timeoutId?: number;
constructor(private alertService: AlertService) {}
ngOnInit(): void {
this.alertService.getAlert().subscribe((alert) => {
this.alert = alert;
this.resetTimer();
});
}
resetTimer(): void {
if (this.timeoutId) {
window.clearTimeout(this.timeoutId);
}
this.timeoutId = window.setTimeout(() => {
this.alert = undefined;
}, 3000);
}
}
Here are changes that we need to do to our AlertComponent
. Every time when we get an alert we create setTimeout
for 3 seconds. After 3 seconds we set alert back to undefined
. We also clean old setTimeout
every time when we get a new alert so we don't accidentally close our new alert.
Now our alert is fully ready.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done