Make writing a habit together! This is the fourth day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

In a previous article about Angular development, we mentioned:

A service can be used for more than just API requests

For example, the implementation of Notification that we will cover in this article.

The renderings are as follows:

The UI can be adjusted later

So, let’s break it down step by step.

Add the service

We add notification. Service. Ts service file (please use command line to generate) to app/services and add relevant content:

// notification.service.ts

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

// Enumeration of notification states
export enum NotificationStatus {
  Process = "progress",
  Success = "success",
  Failure = "failure",
  Ended = "ended"
}

@Injectable({
  providedIn: 'root'
})
export class NotificationService {

  private notify: Subject<NotificationStatus> = new Subject();
  public messageObj: any = {
    primary: ' '.secondary: ' '
  }

  // Convert to observable
  public getNotification(): Observable<NotificationStatus> {
    return this.notify.asObservable();
  }

  // Notification in progress
  public showProcessNotification() {
    this.notify.next(NotificationStatus.Process)
  }

  // Success notification
  public showSuccessNotification() {
    this.notify.next(NotificationStatus.Success)
  }

  // End notification
  public showEndedNotification() {
    this.notify.next(NotificationStatus.Ended)
  }

  // Change the information
  public changePrimarySecondary(primary? :string, secondary? :string) {
    this.messageObj.primary = primary;
    this.messageObj.secondary = secondary
  }

  constructor(){}}Copy the code

Isn’t it easy to understand…

We made Notify an observable object, and then published information about various states.

Create components

We create a new Notification component in app/ Components, where the common components are stored. So you get the following structure:

Notification ├ ─ ─ notification.com ponent. / / HTML page skeleton ├ ─ ─ notification.com ponent. SCSS / / page unique style ├ ─ ─ Notification.com ponent. Spec. Ts / / test file └ ─ ─ notification.com ponent. Ts / / javascript filesCopy the code

We define the skeleton of Notification:

<! -- notification.component.html -->

<! -- Support to manually turn off notifications -->
<button (click) ="closeNotification()">Shut down</button>
<h1>{{message}}</h1>
<! -- Customize key notification information -->
<p>{{ primaryMessage }}</p>
<! -- Customize secondary notification information -->
<p>{{ secondaryMessage }}</p>
Copy the code

Next, we’ll simply retouch the skeleton and add the following styles:

// notification.component.scss

:host {
  position: fixed;
  top: -100%;
  right: 20px;
  background-color: # 999;
  border: 1px solid # 333;
  border-radius: 10px;
  width: 400px;
  height: 180px;
  padding: 10px;
  // Notice the content of active only when the notification appears
  &.active {
    top: 10px;
  }
  &.success {}
  &.progress {}
  &.failure {}
  &.ended{}}Copy the code

The four class names, Success, Progress, Failure, and Ended, correspond to enumerations defined by the Notification Service, and you can add styles as you like.

Finally, we add the behavioral javascript code.

// notification.component.ts

import { Component, OnInit, HostBinding, OnDestroy } from '@angular/core';
// New point RXJS
import { Subscription } from 'rxjs';
import {debounceTime} from 'rxjs/operators';
// Import related services
import { NotificationStatus, NotificationService } from 'src/app/services/notification.service';

@Component({
  selector: 'app-notification'.templateUrl: './notification.component.html'.styleUrls: ['./notification.component.scss']})export class NotificationComponent implements OnInit.OnDestroy {
  
  // Buffeting time, read only
  private readonly NOTIFICATION_DEBOUNCE_TIME_MS = 200;
  
  protectednotificationSubscription! : Subscription;private timer: any = null;
  public message: string = ' '
  
  // Mapping of enumeration information for notification Service
  private reflectObj: any = {
    progress: "In progress".success: "Success".failure: "Failure".ended: "The end"
  }

  @HostBinding('class') notificationCssClass = ' ';

  publicprimaryMessage! :string;
  publicsecondaryMessage! :string;

  constructor(
    private notificationService: NotificationService
  ) { }

  ngOnInit(): void {
    this.init()
  }

  public init() {
    // Add related subscription information
    this.notificationSubscription = this.notificationService.getNotification()
      .pipe(
        debounceTime(this.NOTIFICATION_DEBOUNCE_TIME_MS)
      )
      .subscribe((notificationStatus: NotificationStatus) = > {
        if(notificationStatus) {
          this.resetTimeout();
          // Add related styles
          this.notificationCssClass = `active ${ notificationStatus }`
          this.message = this.reflectObj[notificationStatus]
          // Get custom primary information
          this.primaryMessage = this.notificationService.messageObj.primary;
          // Get custom secondary information
          this.secondaryMessage = this.notificationService.messageObj.secondary;
          if(notificationStatus === NotificationStatus.Process) {
            this.resetTimeout()
            this.timer = setTimeout(() = > {
              this.resetView()
            }, 1000)}else {
            this.resetTimeout();
            this.timer = setTimeout(() = > {
              this.notificationCssClass = ' '
              this.resetView()
            }, 2000)}}})}private resetView(): void {
    this.message = ' '
  }
  
  // Turn off the timer
  private resetTimeout(): void {
    if(this.timer) {
      clearTimeout(this.timer)
    }
  }

  // Turn off notifications
  public closeNotification() {
    this.notificationCssClass = ' '
    this.resetTimeout()
  }
  
  // Component destruction
  ngOnDestroy(): void {
    this.resetTimeout();
    // Cancel all subscription messages
    this.notificationSubscription.unsubscribe()
  }

}
Copy the code

Here, we introduced RXJS, a library for reactive programming using Observables, which makes it easier to write asynchronous or callback-based code. This is a great library, and you’ll learn more about it in the next few articles.

Here we use the Debounce function, which means that after an event is triggered, it can only be executed once after n seconds, and if another event is triggered within n seconds, the execution time of the function is recalculated. In simple terms: When an action is triggered consecutively, it is executed only once.

Ps: throttle specifies that a function can be executed only once in a specified period of time.

During an interview, interviewers love to ask…

call

Because this is a global service, we call this component in app.component.html:

// app.component.html

<router-outlet></router-outlet>
<app-notification></app-notification>
Copy the code

To facilitate the demonstration, we added a button in user-list.component.html to trigger the demonstration:

// user-list.component.html

<button (click) ="showNotification()">click show notification</button>
Copy the code

Trigger the relevant code:

// user-list.component.ts

import { NotificationService } from 'src/app/services/notification.service';

// ...
constructor(
  private notificationService: NotificationService
){}// Display notifications
showNotification(): void {
  this.notificationService.changePrimarySecondary('Main Message 1');
  this.notificationService.showProcessNotification();
  setTimeout(() = > {
    this.notificationService.changePrimarySecondary('Main Message 2'.'Secondary Information 2');
    this.notificationService.showSuccessNotification();
  }, 1000)}Copy the code

Now that we’re done, we’ve successfully simulated the functionality of Notification. You can modify related service components based on actual requirements and customize them to meet service requirements. If we are developing systems for internal use, we recommend using mature UI libraries, which have helped us encapsulate various components and services, saving us a lot of development time.

【 the 】 ✅