Implementing and consuming a notification service
Tags: angular, typescript, beginners, tutorial
Published: 2022-10-07 20:58:36

In this post we are going to see one way we can implement a notification Angular service that can be used in different pages or use cases in our app.

## What is needed before working in our service?

- This example was done in Angular 14 and RXjs 6

- We need to create a shared module that is going to expose our notification component. Remember that a shared module is a module that is included in the file _app.module.ts_ when we do that, we are making the module available all over our app.

```typescript
import { SharedModule } from './shared/shared.module';

@NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        AppRoutingModule,
        SharedModule,
        BrowserAnimationsModule,
    ],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}
```

## Create the service via CLI
The first step is simply generating our service by the following command

```bash
ng g s shared/services/notification
```
you can place the service wherever you want, in my case I chose the shared folder because the service follows the principle of being available to other modules in the app.

## Implementing notification service
For the sake of Typescript principles, we will use an interface for typing the notification object that is going to "travel" through our service.

```typescript
export enum NotificationType {
  success = 'is-success',
  danger = 'is-danger',
  warning = 'is-warning',
}

export interface MaNotification {
  title: string;
  message: string;
  type: NotificationType;
}
```
Simply, our notification object will have a title, a message and a type.

Now let's import our notification interface and implement our service.

```typescript
import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { MaNotification } from 'src/app/models/notification.model';

@Injectable({
    providedIn: 'root',
})
export class NotificationService {
    private notifyRequest = new ReplaySubject<MaNotification>();

    notifyRequest$ = this.notifyRequest.asObservable();

    constructor() {}

    notify(notification: MaNotification) {
        this.notifyRequest.next(notification);
    }
}
```
So, what do we see here? 

1. We see the annotation Injectable that has the attribute providedIn, this setting is allowing us to use our service all over the app. 

2. We notice that we have a private attribute named notifyRequest, this is a ReplaySubject object (a ReplaySubject is an observable and it emits/send values to the observers subscribed to it)

3. we can also see another attribute and this one is not private. this attribute is an observable that is going to be used by the notification component to react when a new value is received (we will see this later). 

4. finally, we see a notify method. This method is going to be used by the service consumers that are interested in display a notification (we will see this later). 

## Create the component via CLI
Obviously, a notification needs to be visual. So, we create our component as follows

```bash
ng g s shared/component/notification
```

Once the component is generated, we need to make it available to the consumers (other pieces of the app like components, etc.). We do that by adding our component to the exports array in our shared module as follows

```typescript
import { NotificationComponent } from './components/notification/notification.component';

@NgModule({
    declarations: [NotificationComponent,],
    // providers, imports go here
    exports: [NotificationComponent],
})
export class SharedModule {}
```

Of course, your shared module will contain more stuff / code. Here I am just focusing the code on what is connected to our notification implementation.

Before implementing a our component, remember the enum we created previously NotificationType. The values of such enum fit the classes from material design css library.

Now we will implement the component logic as follows

```typescript
import { Component, OnInit } from '@angular/core';
import { debounceTime, map, tap } from 'rxjs/operators';
import {
    MaNotification,
    NotificationType,
} from 'src/app/models/notification.model';

//Importing our notification service
import { NotificationService } from '../../services/notification/notification.service';

@Component({
    selector: 'ma-notification',
    templateUrl: './notification.component.html',
    styleUrls: ['./notification.component.scss'],
})
export class NotificationComponent implements OnInit {
    //Flag that is going to be used in the view to determine if the notification should be visible or not.
    showNotification: boolean = false;

//Notification object with the data that is going to be showed.
    incommingNotification: MaNotification = {
        title: '',
        message: '',
        type: NotificationType.danger,
    };

    constructor(private notificationService: NotificationService) {}

    ngOnInit(): void {
       //We subscribe or listens to new values / notification requests.
        this.notificationService.notifyRequest$
            .pipe(
//we receive new notification and update the values of the notification object we have in this component.
// we alse make the notification visible.
                tap((notification: MaNotification) => {
                    this.incommingNotification = notification;
                    this.showNotification = true;
                }),
//we wait for 3 seconds before updating the visibility of the notification
                debounceTime(3000),
//3 seconds later, we make our notification invisible again and ready for the value.
                tap(() => {
                    this.showNotification = false;
                })
            )
            .subscribe();
    }
```
Perfect, now let's see the visual part of our component.

```html
<div
    [class.is-visible-notification]="showNotification"
    class="ma-notification"
    [class]="incommingNotification.type"
>
    <h3 class="ma-notification-title">
        {{ incommingNotification.title }}
    </h3>
    <p class="ma-notification-paragraph">{{ incommingNotification.message }}</p>
</div>
```
Simple, right? 

By means of a css class we control the visibility, and you can also see that incommingNotification.type set the value of a class, such value fits with a Material Design built-in class and in that way, we set the color. If you don't use MD you just need to set css classes that set the color to the div (a "danger" class, "warning" class, etc.).

## But how to consume this service?

We will consume it in a hypothetic login component page

```typescript
import { Component, OnInit } from '@angular/core';

import { NotificationType } from 'src/app/models/notification.model';
import { NotificationService } from 'src/app/shared/services/notification/notification.service';
import { LoginRequest } from '../../../shared/services/user/user.model';
import { UserService } from '../../../shared/services/user/user.service';

const { home } = environment.pages;

@Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss'],
})
export class LoginComponent implements OnInit {
    constructor(
        private notificationService: NotificationService
    ) {
    }

    ngOnInit(): void {}

    async handleSubmit(loginRequest: LoginRequest): Promise<void> {
        const signInRes = await this.userService.authenticate(loginRequest);
        if (signInRes.error) {
            this.notificationService.notify({
                title: 'Oh Oh 😕',
                type: NotificationType.danger,
                message: signInRes.error.message,
            });
        }
    }
}
```