npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@libs-ui/services-notification

v0.2.357-4

Published

> Service toast notification cho Angular — hiển thị 4 kiểu thông báo (success, error, info, warn), quản lý queue tự động, tích hợp ngx-translate, và hỗ trợ bridge sang micro-frontend qua iFrame messaging.

Downloads

4,629

Readme

@libs-ui/services-notification

Service toast notification cho Angular — hiển thị 4 kiểu thông báo (success, error, info, warn), quản lý queue tự động, tích hợp ngx-translate, và hỗ trợ bridge sang micro-frontend qua iFrame messaging.

Giới thiệu

LibsUiNotificationService là service singleton (providedIn: 'root') dùng để hiển thị toast notification động trực tiếp vào document.body thông qua LibsUiDynamicComponentService. Service tự quản lý queue tối đa 5 thông báo đồng thời theo cơ chế FIFO, tự động stack vị trí các toast, và có khả năng phát hiện môi trường iFrame để bridge thông báo lên parent shell trong kiến trúc micro-frontend.

Tính năng

  • ✅ 4 kiểu toast: success (xanh lá), error (đỏ), info (xanh dương), warn (vàng)
  • ✅ Queue tối đa 5 — FIFO auto-remove khi overflow
  • ✅ Tích hợp ngx-translate — truyền translation key hoặc text thường đều được
  • interpolateParams với XSS-safe escaping tự động qua escapeHtml()
  • ✅ Callback onClick / onMouseenter trên từng toast
  • ✅ Tùy chỉnh timeRemove (ms) và positionRight (px)
  • ✅ Dynamic stacking — tự tính lại vị trí top/right sau mỗi add/remove
  • ✅ iFrame bridge cho micro-frontend — tự phát hiện isEmbedFrame() và gửi PostMessage lên parent
  • ✅ Browser native Notification API (systemSpawnNotification) trả về Observable

Khi nào sử dụng

  • Thông báo kết quả sau action: lưu, xóa, cập nhật — dùng success hoặc error
  • Thông báo lỗi hệ thống hoặc lỗi network API — dùng error hoặc warn
  • Thông báo thông tin cho user (tips, hướng dẫn ngắn) — dùng info
  • Cần hiển thị notification từ micro-frontend (child iFrame) lên parent shell — dùng init() + iFrame bridge
  • Cần push native OS/browser notification khi tab không active — dùng systemSpawnNotification()

Cài đặt

npm install @libs-ui/services-notification

Import

import { LibsUiNotificationService } from '@libs-ui/services-notification';

Service được đăng ký providedIn: 'root' — không cần thêm vào providers[] của module hay component.

Ví dụ sử dụng

1. Cơ bản — 4 kiểu toast

import { Component, inject } from '@angular/core';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-example',
  template: `
    <button (click)="handlerSave()">Lưu</button>
    <button (click)="handlerDelete()">Xóa</button>
  `,
})
export class ExampleComponent {
  private readonly notif = inject(LibsUiNotificationService);

  handlerSave() {
    this.notif.showCompTypeTextSuccess('Lưu thành công!');
  }

  handlerDelete() {
    this.notif.showCompTypeTextError('Xóa thất bại. Vui lòng thử lại.');
  }

  handlerInfo() {
    this.notif.showCompTypeTextInfo('Phiên làm việc sẽ hết hạn sau 5 phút.');
  }

  handlerWarning() {
    this.notif.showCompTypeTextWarning('Dung lượng lưu trữ gần đầy.');
  }
}

2. Đầy đủ config — title, timeRemove, positionRight, callback

import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-create-user',
  template: `<button (click)="handlerCreate()">Tạo tài khoản</button>`,
})
export class CreateUserComponent {
  private readonly notif = inject(LibsUiNotificationService);
  private readonly router = inject(Router);

  handlerCreate() {
    this.notif.showCompTypeTextSuccess('Tạo tài khoản thành công!', {
      title: 'Thành công',         // tiêu đề (optional)
      timeRemove: 5000,            // ms — tự động đóng sau 5 giây (default: 3000)
      positionRight: 24,           // px từ phải màn hình (default: 12)
      eventName: 'click',          // 'click' | 'mouseenter' — trigger callback
      callback: () => this.router.navigate(['/users']),
      interpolateParams: {         // params cho ngx-translate interpolation (tự động escaped)
        name: 'Nguyễn Văn A',
      },
    });
  }
}

3. Dùng với ngx-translate key và interpolation

import { Component, inject } from '@angular/core';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-report',
  template: `<button (click)="handlerDelete()">Xóa báo cáo</button>`,
})
export class ReportComponent {
  private readonly notif = inject(LibsUiNotificationService);

  handlerDelete() {
    // Truyền translation key — ngx-translate xử lý tự động
    this.notif.showCompTypeTextSuccess('notifications.save_success');

    // Với interpolation params (tự động escape HTML để ngăn XSS):
    this.notif.showCompTypeTextError('notifications.delete_error', {
      interpolateParams: { itemName: 'Báo cáo tháng 1' },
    });
    // JSON: { "notifications": { "delete_error": "Không thể xóa '{{itemName}}'. Vui lòng thử lại." } }
    // Kết quả: "Không thể xóa 'Báo cáo tháng 1'. Vui lòng thử lại."
  }
}

4. Callback khi user tương tác với toast

import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-inbox',
  template: `<button (click)="handlerNewMessage()">Kiểm tra tin nhắn</button>`,
})
export class InboxComponent {
  private readonly notif = inject(LibsUiNotificationService);
  private readonly router = inject(Router);

  handlerNewMessage() {
    // Callback khi user click vào toast
    this.notif.showCompTypeTextInfo('Bạn có thông báo mới. Click để xem.', {
      eventName: 'click',
      timeRemove: 8000,
      callback: () => {
        this.router.navigate(['/notifications']);
      },
    });
  }

  handlerStorageWarning() {
    // Callback khi user hover vào toast
    this.notif.showCompTypeTextWarning('Dung lượng gần đầy. Hover để xem chi tiết.', {
      eventName: 'mouseenter',
      timeRemove: 6000,
      callback: () => this.showStorageDetail(),
    });
  }

  private showStorageDetail() {
    // xử lý hiển thị chi tiết
  }
}

5. iFrame Bridge — Micro-frontend

// === AppComponent của Shell (parent) ===
import { Component, inject } from '@angular/core';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-root',
  template: `<router-outlet />`,
})
export class AppComponent {
  private readonly notif = inject(LibsUiNotificationService);

  constructor() {
    // Gọi 1 lần duy nhất — service có guard isInit để tránh duplicate listener
    this.notif.init(
      ['MICRO_SITE_PUSH_MESSAGE_FROM_CHILD'],  // message names để lắng nghe từ child
      'MICRO_SITE_PUSH_MESSAGE_FROM_CHILD',    // tên PostMessage gửi lên parent (optional)
    );
  }
}

// === Micro-frontend child (embedded trong iFrame) ===
// Gọi notification bình thường — service tự phát hiện isEmbedFrame()
// và gửi PostMessage lên parent thay vì render tại chỗ
@Component({
  standalone: true,
  selector: 'app-upload',
  template: `<button (click)="handlerUpload()">Upload</button>`,
})
export class UploadComponent {
  private readonly notif = inject(LibsUiNotificationService);

  handlerUpload() {
    this.notif.showCompTypeTextSuccess('Upload hoàn tất!');
    // → parent shell nhận PostMessage và render notification thay vì child
  }
}

6. Browser Native Notification

import { Component, inject } from '@angular/core';
import { LibsUiNotificationService } from '@libs-ui/services-notification';

@Component({
  standalone: true,
  selector: 'app-push-setup',
  template: `
    <button (click)="handlerRequestPermission()">Bật thông báo</button>
    <button (click)="handlerSpawnNotification()">Gửi thông báo</button>
  `,
})
export class PushSetupComponent {
  private readonly notif = inject(LibsUiNotificationService);

  handlerRequestPermission() {
    // Xin quyền browser native notification
    this.notif.systemRequestPermission();
  }

  handlerSpawnNotification() {
    // Hiển thị native notification (chỉ khi đã granted)
    this.notif
      .systemSpawnNotification('Thông báo mới', {
        body: 'Bạn có 3 tin nhắn chưa đọc từ Team',
        icon: '/assets/icons/icon-192x192.png',
        tag: 'inbox-notification',
      })
      .subscribe({
        next: (event) => {
          // Trả về { notification, event } khi show hoặc click
        },
        error: (err) => {
          // Notification lỗi
        },
        complete: () => {
          // Notification đã đóng
        },
      });
  }
}

Methods (Service)

| Method | Signature | Mô tả | |---|---|---| | showCompTypeTextSuccess | (message: string, config?: INotificationTextPublicConfig): void | Hiển thị toast màu xanh lá — thành công | | showCompTypeTextError | (message: string, config?: INotificationTextPublicConfig): void | Hiển thị toast màu đỏ — lỗi | | showCompTypeTextInfo | (message: string, config?: INotificationTextPublicConfig): void | Hiển thị toast màu xanh dương — thông tin | | showCompTypeTextWarning | (message: string, config?: INotificationTextPublicConfig): void | Hiển thị toast màu vàng — cảnh báo | | init | (messageNameHandler: string[], messageNamePostToParent?: string): void | Khởi tạo iFrame bridge listener — gọi 1 lần trong AppComponent của shell | | systemRequestPermission | (): void | Xin quyền browser native notification | | systemSpawnNotification | (title: string, options?: NotificationOptions): Observable<unknown> | Hiển thị browser native notification, trả về Observable theo vòng đời notification | | get TranslateService | TranslateService | Getter trả về instance của TranslateService đang inject |

Types & Interfaces

import {
  INotificationTextPublicConfig,
  INotificationTextConfig,
  INotificationQueue,
  INotificationPushFromIFrame,
} from '@libs-ui/services-notification';

INotificationTextPublicConfig

Config truyền vào các method showCompTypeText*():

interface INotificationTextPublicConfig {
  title?: string;                          // Tiêu đề hiển thị trên toast
  timeRemove?: number;                     // ms — tự động đóng (default: 3000)
  positionRight?: number;                  // px từ phải màn hình (default: 12)
  eventName?: 'click' | 'mouseenter';      // Event trigger callback
  callback?: () => void;                   // Hàm gọi khi user tương tác
  interpolateParams?: Record<string, any>; // Params ngx-translate (tự động escaped)
}

| Field | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | title | string | undefined | Tiêu đề hiển thị phía trên message trong toast | title: 'Thành công' | | timeRemove | number (ms) | 3000 | Thời gian tự động đóng tính bằng milliseconds | timeRemove: 5000 | | positionRight | number (px) | 12 | Khoảng cách từ phải màn hình tính bằng pixel | positionRight: 24 | | eventName | 'click' \| 'mouseenter' | undefined | Event DOM sẽ trigger callback | eventName: 'click' | | callback | () => void | undefined | Hàm gọi khi user thực hiện event tương ứng | callback: () => router.navigate(['/']) | | interpolateParams | Record<string, any> | undefined | Params truyền vào ngx-translate interpolation, tự động escape HTML | interpolateParams: { name: 'An' } |

INotificationTextConfig (Internal)

Config nội bộ dùng khi tạo component động — thường không dùng trực tiếp:

interface INotificationTextConfig {
  type: 'success' | 'info' | 'error' | 'warn'; // Kiểu toast
  timeRemove: number;                            // ms
  positionRight?: number;                        // px
  zIndex?: number;                               // CSS z-index (default: 2000)
  eventName?: 'click' | 'mouseenter';
  callback?: () => void;
}

INotificationPushFromIFrame (Internal)

Payload nhận từ child iFrame qua PostMessage:

interface INotificationPushFromIFrame {
  functionName: 'success' | 'info' | 'error' | 'warn';
  message: string;
  title?: string;
  timeRemove?: number;
}

Lưu ý quan trọng

⚠️ Queue MAX 5 — FIFO: Nếu đang có đủ 5 toast trên màn hình, toast cũ nhất sẽ tự bị remove (kèm hủy timeout của nó) khi toast mới xuất hiện. Hành vi này không thể tắt.

⚠️ interpolateParams XSS-safe: Mỗi value trong interpolateParams tự động qua escapeHtml() trước khi truyền vào ngx-translate. Đây là bảo vệ XSS cho user-generated content. Message string gốc không bị escape — phải là translation key hoặc text an toàn.

⚠️ init() chỉ gọi 1 lần: Service có guard isInit signal — gọi init() nhiều lần an toàn, chỉ listener đầu tiên được đăng ký. Nên gọi trong AppComponent constructor của shell.

⚠️ iFrame auto-detection: Service tự gọi isEmbedFrame() — không cần config thêm trong child app. Khi chạy trong iFrame, payload được encrypt() trước khi gửi lên parent qua PostMessage.

⚠️ systemSpawnNotification yêu cầu granted: Observable sẽ complete() ngay lập tức nếu browser không hỗ trợ Notification API hoặc quyền chưa được cấp ('granted'). Luôn gọi systemRequestPermission() trước.

⚠️ Dynamic stacking dùng getBoundingClientRect(): Vị trí top/right của các toast được tính lại sau mỗi add/remove thông qua setTimeout để đảm bảo DOM đã render. Tránh can thiệp vào style inline top/right của các element toast từ bên ngoài.

Demo

npx nx serve core-ui

Truy cập: http://localhost:4500/services/notification