Let's build a Nice and Animated Notifications Menu with Angular, Angular Animations and Bootstrap
Tags: angular, tutorial, webdev, codenewbie
Published: 2023-03-09 14:08:02

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40s5fea2aq32b35qhz6r.gif)

___
## ✵ Project Informations

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

```typescript
// 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',
  },
];
```
___
## ✵ Creating the project

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

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

After that open it in your preferred Code Editor.
___

## ✵ Installing Bootstrap and Importing

First, let's install the **Bootstrap** dependency:
```
npm i bootstrap
```
Now, let's import the **Bootstrap** styles, in your **styles.scss** file import it:
```scss
@import "bootstrap/scss/bootstrap";
```
For the scripts, in the scripts array in your `angular.json` file import the **bootstrap.bundle.min.js**, like below:

```javascript
"scripts": [
   "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
],
```
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: 

```html
<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"/>
```
### ➝ 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:

```scss
/* 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;
}
```

> 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
```

And the code will be like below:

```typescript
export interface Notification {
  title: string;
  createdAt: string;
  description: string;
}
```
___
## ✵ Creating and Implementing the Header:

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

```bash
ng g c components/header --standalone
```
Now, for our header structure we'll use the **[bootstrap navbar](https://getbootstrap.com/docs/5.2/components/navbar/#offcanvas)** and we need a button with **[bootstrap offcanvas](https://getbootstrap.com/docs/5.2/components/offcanvas/#via-data-attributes)** properties, so the code will be like below:

```html
<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>
```

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

#### ➝ App Module:
```typescript 
@NgModule({
  ...
  imports: [
    ...
    HeaderComponent,
  ],
  ...
})
```
#### ➝ App Html:
```html
<app-header></app-header>
<router-outlet></router-outlet>
```

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jz5snaqarqxhs9942c3s.png)
___
## ✵ Creating the Card component
Now we will create our `card-notification` standalone component using the **bootstrap card** component! 

### ➝ Generating the component:
```bash
ng g c components/card-notification --standalone
```

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:
```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>
```
#### ➝ Notification Card Class:
```typescript
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Notification } from '../../models/notification';

...

export class CardNotificationComponent {

  @Input() notification: Notification;

}
```
#### ➝ Notification Card Style:
```sass
.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;
  }
}
```

Annd done, now we'd our `card-notification` component 🥳🥳🥳
___ 

## ✵ Creating the menu

We'll use **[bootstrap offcanvas](https://getbootstrap.com/docs/5.2/components/offcanvas/#examples)** to make our menu, so let's generate the `menu-notifications` component and its structure:

### ➝ Generating the component:
```bash
ng g c components/menu-notifications --standalone
```

Now, let's insert the **[bootstrap offcanvas](https://getbootstrap.com/docs/5.2/components/offcanvas/#examples)** 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:
```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>
```

#### ➝ Menu Notification CLASS:
```typescript
...
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.',
    },
  ];
}
```
And here we can see how our project are, take a look:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7jhwdidu2adms5881uz.gif)
___

## ✵ 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`

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

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

### ➝ 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
| 
```

Now our cards will have a `transitionY`, `opacity` and `offset` changes, so our `animations.ts` using **[Angular Animations](https://angular.io/guide/animations)** will look like below:

```typescript
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})
      ])
    ]);
```

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:
```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>

``` 

#### ➝ Menu Notifications CLASS:
```typescript
import { animateListItems } from '../../animations/animations';

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

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:

```typescript

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;
    });
  }
}
```

And finally, we have our animation in the `Notifications Menu` working like a charm 🥳🥹😋🥳🥹😋

Below you can see the animation working:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfrjftvew4yyrw35mf1b.gif)

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.](https://github.com/ferrorenan/angular-menu-notifications)**

And you can forked it, too! 

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

See you later guys 🖖🖖🖖