Let's build a Nice and Animated Notifications Menu with Angular, Angular Animations and Bootstrap

Renan Ferro - Mar 9 '23 - - Dev Community

Hey guys, how are you!?

Today we are going to learn and build a cool animated notifications menu, using Angular standalone components, Angular animations and Bootstrap!

Below you can see our final project and you will be able to reuse the animation and make other animations even more beautiful!

Image description


✡ Project Informations

Here you can find the project informations and the Angular CLI I used to generate the project:



// Project generate with
private readonly generatedInformation = 'Angular CLI 15.2.0';

// Dependencies
const projectInformations: Informations[] = [
  {
    tecnologie: 'Angular',
    version: '15.2.0',
  },
  {
    tecnologie: 'Angular Animations',
    version: '15.2.0',
  },
  {
    tecnologie: 'Bootstrap',
    version: '5.2.3',
  },
];


Enter fullscreen mode Exit fullscreen mode

✡ Creating the project

In your preferred folder, create a new Angular project with router-outlet and with scss:



ng new angular-menu-notifications
---
? Would you like to add Angular routing? Yes
---
? Which stylesheet format would you like to use? SCSS


Enter fullscreen mode Exit fullscreen mode

After that open it in your preferred Code Editor.


✡ Installing Bootstrap and Importing

First, let's install the Bootstrap dependency:



npm i bootstrap


Enter fullscreen mode Exit fullscreen mode

Now, let's import the Bootstrap styles, in your styles.scss file import it:



@import "bootstrap/scss/bootstrap";


Enter fullscreen mode Exit fullscreen mode

For the scripts, in the scripts array in your angular.json file import the bootstrap.bundle.min.js, like below:



"scripts": [
   "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
],


Enter fullscreen mode Exit fullscreen mode

Niice, now we have the Bootstrap already for us and we can use it!

Let's implement the structure πŸ˜‹πŸ˜‹


✡ Styling the project:

➝ Importing the Google Fonts:

In your index.html inside of the head tag let's import the
Google Poppins font API:



<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;600&display=swap" rel="stylesheet"/>


Enter fullscreen mode Exit fullscreen mode

➝ Styling the global style's project:

Now, let's change some bootstrap classes styles, so in our styles.scss let's insert the code below:



/* You can add global styles to this file, and also import other style files */
@import "bootstrap/scss/bootstrap";

$primary: #1e1e1e;
$secondary: #181818;
$warning: #C5F7C9;

.bg-primary {

  background-color: $primary !important;
}

.bg-secondary {

  background-color: $secondary !important;
}

.text-warning {

  color: $warning !important;
}

.border-warning {

  border-color: $warning !important;
}

.offcanvas {

  width: 450px !important;
  padding: 0 1rem;
}

.text-bg-warning {

  background-color: $warning !important;
}

body {

  min-height: 100vh;
  background-color: $primary;
}


Enter fullscreen mode Exit fullscreen mode

I don't really like to insert styling code in this file, I prefer to create a resources folder and isolate it in some folders/files with style properties! I prefer to do this so that the project is more organized and easier to maintain. But this example is a small project, so let's do it like the example!


✡ Creating the Notification Model

Our notification will have three properties, title, createdAt, description, so let's generate the model and insert the properties:



ng g i models/notifications


Enter fullscreen mode Exit fullscreen mode

And the code will be like below:



export interface Notification {
  title: string;
  createdAt: string;
  description: string;
}


Enter fullscreen mode Exit fullscreen mode

✡ Creating and Implementing the Header:

Let's generate our standalone header component in a components folder, so to generate we write:



ng g c components/header --standalone


Enter fullscreen mode Exit fullscreen mode

Now, for our header structure we'll use the bootstrap navbar and we need a button with bootstrap offcanvas properties, so the code will be like below:



<header>
  <nav class="navbar navbar-dark bg-secondary">
    <div class="container-fluid">
      <button class="ms-auto navbar-toggler"
              type="button"
              data-bs-toggle="offcanvas"
              data-bs-target="#offcanvasNotifications"
              aria-controls="offcanvasNotifications">
        <span class="navbar-toggler-icon"></span>
      </button>
    </div>
  </nav>
</header>


Enter fullscreen mode Exit fullscreen mode

Now we need to import it in your app.module.ts and insert in the app.component.html:

➝ App Module:



@NgModule({
  ...
  imports: [
    ...
    HeaderComponent,
  ],
  ...
})


Enter fullscreen mode Exit fullscreen mode

➝ App Html:



<app-header></app-header>
<router-outlet></router-outlet>


Enter fullscreen mode Exit fullscreen mode

And now our project will be like below, with the header and styles configuration:

Image description


✡ Creating the Card component

Now we will create our card-notification standalone component using the bootstrap card component!

➝ Generating the component:



ng g c components/card-notification --standalone


Enter fullscreen mode Exit fullscreen mode

We will have three properties, title, createdAt and description as our Notification interface! And the card-notification will receive the notification with the @Input() bind, our card-notification code will be as below:

➝ Notification Card HTML:



<div class="bg-primary border-warning card">
  <div class="card-body">
    <h3 class="text-warning fw-bold card-title">
      {{ notification.title }}
    </h3>
    <span class="badge text-bg-warning card-date">
      {{ notification.createdAt }}
    </span>
    <p class="card-text">
      {{ notification.description }}
    </p>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

➝ Notification Card Class:



import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Notification } from '../../models/notification';

...

export class CardNotificationComponent {

  @Input() notification: Notification;

}


Enter fullscreen mode Exit fullscreen mode

➝ Notification Card Style:



.card {

  border-radius: 25px;
  margin-bottom: 1.5rem;
  border-width: 2px;
  border-style: solid;
  color: white;

  &-title {
    font-size: 1rem;
    font-family: 'Poppins', sans-serif;
    font-weight: 500;
  }

  &-date {
    font-size: 0.75rem;
    margin-bottom: 0.75rem;
    border-radius: 5px;
  }

  &-text {
    font-size: 0.825rem;
    font-family: 'Poppins', sans-serif;
    font-weight: 300;
  }
}


Enter fullscreen mode Exit fullscreen mode

Annd done, now we'd our card-notification component πŸ₯³πŸ₯³πŸ₯³


✡ Creating the menu

We'll use bootstrap offcanvas to make our menu, so let's generate the menu-notifications component and its structure:

➝ Generating the component:



ng g c components/menu-notifications --standalone


Enter fullscreen mode Exit fullscreen mode

Now, let's insert the bootstrap offcanvas structure, insert the card-notification component inside the offcanvas-body and inside it we'll make an ng-container with *ngFor to display some dummy notifications created in our menu-notification.component.ts, and it will be like:

➝ Menu Notification HTML:



<div class="offcanvas offcanvas-end bg-secondary"
     data-bs-backdrop="static"
     tabindex="-1"
     id="offcanvasNotifications"
     aria-labelledby="offcanvasNotificationsLabel">
  <div class="offcanvas-header">
    <h2 class="h5 text-white offcanvas-title"
        id="offcanvasNotificationsLabel">
      All Notifications
    </h2>
    <button type="button"
            class="btn-close"
            data-bs-dismiss="offcanvas"
            aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <ng-container *ngFor="let notification of notificationsMockup">
      <app-card-notification [notification]="notification"></app-card-notification>
    </ng-container>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

➝ Menu Notification CLASS:



...
import { Notification } from '../../models/notification';
import {
  CardNotificationComponent
} from '../card-notification/card-notification.component';

@Component({
  ...
  imports: [
      CommonModule,
      CardNotificationComponent
  ],
  ...
})
export class MenuNotificationsComponent {

  notificationsMockup: Notification[] = [
    {
      title: 'What is Lorem Ipsum?',
      createdAt: '2023-02-21',
      description:
          'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    },
    {
      title: 'What is Lorem Ipsum?',
      createdAt: '2023-02-21',
      description:
          'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    },
    {
      title: 'What is Lorem Ipsum?',
      createdAt: '2023-02-21',
      description:
          'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    },
    {
      title: 'What is Lorem Ipsum?',
      createdAt: '2023-02-21',
      description:
          'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    },
  ];
}


Enter fullscreen mode Exit fullscreen mode

And here we can see how our project are, take a look:

Image description


✡ Implementing the Angular Animation

Now let's implement Angular Animation and make our menu notifications cooler!

First, when we use Angular Animation we need to import the BrowserAnimationsModule, so let's import it into our app.module.ts



...
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  ...
  imports: [
    ...
    BrowserAnimationsModule,
    ...
  ],
  ...
})
export class AppModule { }


Enter fullscreen mode Exit fullscreen mode

➝ Creating the Animation:

First let's create an animations folder in our app folder and inside it we'll create an animations.ts. file, so the structure of the folder will look like this:



| src
| ---animations
| -----animations.ts
| 


Enter fullscreen mode Exit fullscreen mode

Now our cards will have a transitionY, opacity and offset changes, so our animations.ts using Angular Animations will look like below:



import { animate, keyframes, query, stagger, state, style, transition, trigger } from '@angular/animations';

export const animateListItems =
    trigger('listAnimation', [
      transition('* => *', [
        query(':enter', style({
          opacity: 0,
        }), {optional: true}),
        query(':enter', stagger('300ms', [
          animate('1.3s ease-in', keyframes([
            style({opacity: 0, transform: 'translateY(380px)', offset: 0}),
            style({opacity: .5, transform: 'translateY(-8px)', offset: 0.5}),
            style({opacity: 1, transform: 'translateY(0)', offset: 1}),
          ]))
        ]), {optional: true})
      ])
    ]);


Enter fullscreen mode Exit fullscreen mode

Now, let's add some new structures to our menu-notifications.component.html and import the animation.ts inside the animations array in menu-notifications.component.ts:

➝ Menu Notifications HTML:



<div class="offcanvas offcanvas-end bg-secondary"
     data-bs-backdrop="static"
     tabindex="-1"
     id="offcanvasNotifications"
     aria-labelledby="offcanvasNotificationsLabel">
  ...
  <div class="offcanvas-body">
    <ng-container *ngIf="showNotificationsContainer">
      <div [@listAnimation]="notificationsMockup.length">
        <div *ngFor="let notification of notificationsMockup">
          <app-card-notification [notification]="notification"></app-card-notification>
        </div>
      </div>
    </ng-container>
  </div>
</div>



Enter fullscreen mode Exit fullscreen mode

➝ Menu Notifications CLASS:



import { animateListItems } from '../../animations/animations';

@Component({
  ...
  animations: [
    animateListItems
  ]
})


Enter fullscreen mode Exit fullscreen mode

And lastly, we need to apply the animation when the [shown.bs.offcanvas](https://getbootstrap.com/docs/5.2/components/offcanvas/#events) events occur in our #offcanvasNotifications, so inside the menu-notifications.component.ts we will insert the method below:




export class MenuNotificationsComponent implements OnInit  {

  showNotificationsContainer = false;

  ...

  ngOnInit(): void {

    this.listEndAnimationenOpenOffCanvas();
  }

  listEndAnimationenOpenOffCanvas(): void {

    const notificationsOffcanvas = document.getElementById('offcanvasNotifications');

    if (!notificationsOffcanvas){
      return;
    }

    notificationsOffcanvas.addEventListener('shown.bs.offcanvas', () => {

      console.log('entrou');
      this.showNotificationsContainer = true;
    });
  }
}


Enter fullscreen mode Exit fullscreen mode

And finally, we have our animation in the Notifications Menu working like a charm πŸ₯³πŸ₯ΉπŸ˜‹πŸ₯³πŸ₯ΉπŸ˜‹

Below you can see the animation working:

Image description

Now we have our notifications menu animated using Angular animations and fully reusable!

And we can use our imagination now to enhance and create other wonderful animations!


If you liked the project, please give a star in the repository: Github Repository.

And you can forked it, too!

I hope you enjoyed it and that this article helps you!

See you later guys πŸ––πŸ––πŸ––

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .