In the previous article, we mentioned that
service can not only be used to process API requests, but also has other uses
, such as the implementation of notification
that we will talk about in this article. [Recommended related tutorials: "Angular Tutorial"]
The renderings are as follows:
The UI can be adjusted later
, so let’s break it down step by step.
To add a service,
we add the notification.service.ts
service file in app/services
(please use the command line to generate it) and add related content:
// notification.service.ts import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; // Enumeration of notification status 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 an 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 information public changePrimarySecondary(primary?: string, secondary?: string) { this.messageObj.primary = primary; this.messageObj.secondary = secondary } constructor() { } }
Is it easy to understand...
We turn notify
into an observable object, and then publish various status information.
To create a component,
we create a new notification
component in app/components
where public components are stored. So you will get the following structure:
notification ├── notification.component.html // Page skeleton ├── notification.component.scss // Page unique style ├── notification.component.spec.ts // Test file └── notification.component.ts // In the javascript file
we define the skeleton of notification
:
<!-- notification.component.html --> <!--Support manual closing of notifications--> <button (click)="closeNotification()">Close</button> <h1>Reminder content: {{ message }}</h1> <!-- Customize key notification information--> <p>{{ primaryMessage }}</p> <!-- Customize secondary notification information--> <p>{{ secondaryMessage }}</p>
Next, we simply modify the skeleton and add the following style:
// 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; // Pay attention to the content of active here. It only appears when a notification appears. &.active { top: 10px; } &.success{} &.progress {} &.failure {} &.ended {} }
The four class names of success, progress, failure, ended
correspond to the enumeration defined by the notification service. You can add related styles according to your own preferences.
Finally, we add the behavioral javascript
code.
// notification.component.ts import { Component, OnInit, HostBinding, OnDestroy } from '@angular/core'; //New knowledge point rxjs import { Subscription } from 'rxjs'; import {debounceTime} from 'rxjs/operators'; //Introduce 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 { // Anti-shake time, read-only private readonly NOTIFICATION_DEBOUNCE_TIME_MS = 200; protected notificationSubscription!: Subscription; private timer: any = null; public message: string = '' // notification service mapping of enumeration information private reflectObj: any = { progress: "in progress", success: "success", failure: "failure", ended: "end" } @HostBinding('class') notificationCssClass = ''; public primaryMessage!: string; public secondaryMessage!: string; constructor( private notificationService: NotificationService ) { } ngOnInit(): void { this.init() } public init() { //Add relevant 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 message 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 = '' } // Close the timer private resetTimeout(): void { if(this.timer) { clearTimeout(this.timer) } } // Close notification public closeNotification() { this.notificationCssClass = '' this.resetTimeout() } // Component is destroyed ngOnDestroy(): void { this.resetTimeout(); //Cancel all subscription messages this.notificationSubscription.unsubscribe() } }
Here, we introduce the knowledge point of rxjs . RxJS is a reactive programming library 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
anti-shake function. Function anti-shake means that after an event is triggered, it can only be executed once after n seconds. If the event is triggered again within n seconds, the execution time of the function will be recalculated. To put it simply: when an action is triggered continuously, only the last time is executed.
ps:
throttle
throttling function: restrict a function to be executed only once within a certain period of time .
During the interview, the interviewer likes to ask...
Calling
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>
In order to facilitate the demonstration, we add a button in user-list.component.html
to easily trigger the demonstration:
// user-list.component.html <button (click)="showNotification()">click show notification</button>
triggers the relevant code:
// user-list.component.ts import { NotificationService } from 'src/app/services/notification.service'; // ... constructor( private notificationService: NotificationService ) { } //Show notification showNotification(): void { this.notificationService.changePrimarySecondary('Primary information 1'); this.notificationService.showProcessNotification(); setTimeout(() => { this.notificationService.changePrimarySecondary('Primary information 2', 'Secondary information 2'); this.notificationService.showSuccessNotification(); }, 1000) }
At this point, we are done, we have successfully simulated the notification
function. We can modify related service components according to actual needs and customize them to meet business needs. If we are developing a system for internal use, it is recommended to use mature UI libraries. They have helped us encapsulate various components and services, saving us a lot of development time.