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

@touhidrahman/ngx-common

v1.1.0

Published

- [Installation](#installation) - [Directives](#directives) - [Pipes](#pipes) - [Services](#services) - [Models](#models) - [Utility Functions](#utility-functions) - [Peer Dependencies](#peer-dependencies)

Downloads

402

Readme

Table of Contents


Installation

npm install @touhidrahman/ngx-common

Directives

ngxClickOutside

Emits an event when the user clicks outside the host element.

<div (clickOutside)="onClickedOutside($event)" ngxClickOutside>
    Click outside this div to trigger
</div>
onClickedOutside(event: MouseEvent): void {
  console.log('Clicked outside');
}

ngxCopyToClipboard

Copies the bound text to the clipboard when the element is clicked.

<button [ngxCopyToClipboard]="'Text to copy'">Copy</button>
// Standalone
import { CopyToClipboardDirective } from '@touhidrahman/ngx-common'

ngxDisableNullHref

Prevents navigation on anchor elements when the href is not a valid URL.

<a href="" ngxDisableNullHref>Will not navigate</a>
<a href="https://example.com" ngxDisableNullHref>Will navigate</a>

a[download] (DownloadDirective)

Downloads files by fetching cross-origin URLs as blobs. Provides loading and error public properties via a template reference.

<a
    download="report.pdf"
    href="https://example.com/report.pdf"
    #downloader="appDownload"
>
    Download
</a>
<span *ngIf="downloader.loading">Downloading...</span>
<span *ngIf="downloader.error">Download failed</span>

Dependencies: HttpClient, DomSanitizer


ngxHide

Toggles visibility: hidden on the element (element still occupies space, unlike *ngIf).

<div [ngxHide]="isHidden">This div hides but keeps its space</div>

ngxOnClickGoBack

Navigates the browser back one step in history on click.

<button ngxOnClickGoBack>Go Back</button> <a ngxOnClickGoBack>Back</a>

ngxRepeat (structural directive)

Repeats the host element's content a specified number of times. Exposes the current index in the context.

<div *ngxRepeat="5; let i = index">Item #{{ i + 1 }}</div>
// Standalone
import { RepeatDirective } from '@touhidrahman/ngx-common'

ngxScrollable

Adds scroll control capabilities: check overflow, scroll programmatically, and detect scroll boundaries.

<div #scrollRef="ngxScrollable" ngxScrollable [scrollUnit]="200">
    <div
        *ngFor="let item of items"
        style="display: inline-block; width: 200px;"
    >
        {{ item }}
    </div>
</div>
<button (click)="scrollRef.scroll(-1)" [disabled]="!scrollRef.canScrollStart">
    Left
</button>
<button (click)="scrollRef.scroll(1)" [disabled]="!scrollRef.canScrollEnd">
    Right
</button>

| Property/Method | Type | Description | | ------------------- | ------ | ------------------------------------------------- | | scrollUnit | Input | Pixels to scroll per scroll() call | | isOverflow | Getter | Whether content overflows the container width | | canScrollStart | Getter | Whether the user can scroll left | | canScrollEnd | Getter | Whether the user can scroll right | | scroll(direction) | Method | Scrolls left (-1) or right (1) by scrollUnit px |


img[ngxUseFallbackImage]

Shows a transparent 1x1 placeholder when the image source is empty or fails to load.

<img [src]="user.avatarUrl" ngxUseFallbackImage />

Pipes

bytes

Converts a number of bytes into a human-readable format.

{{ 2048 | bytes }}              // "2 kB"
{{ 2048 | bytes:2 }}            // "2.00 kB"
{{ 1048576 | bytes:0:'B':'MB' }} // "1 MB"

bytes:decimals:fromUnit:toUnit


ceiling

Rounds a number up (Math.ceil).

{{ 4.2 | ceiling }}  // 5
{{ -4.2 | ceiling }} // -4

fileSize

Formats a byte count into a file size string with configurable unit and decimals.

{{ 1234567 | fileSize }}          // "1.18 MB"
{{ 1234567 | fileSize:'KB':2 }}   // "1205.63 KB"
{{ 0 | fileSize }}                // "0 B"

fileSize:unit:decimals — unit is 'auto', 'B', 'KB', 'MB', 'GB', or 'TB'.


filter

Filters an array of objects by matching properties case-insensitively.

const items = [{ name: 'John' }, { name: 'Jane' }];

{{ items | filter:{ name: 'john' } }}  // [{ name: 'John' }]

floor

Rounds a number down (Math.floor).

{{ 4.9 | floor }}  // 4
{{ -4.9 | floor }} // -5

initialName

Returns the first character of a string, uppercased.

{{ 'john' | initialName }} // "J"
{{ '' | initialName }}     // ""

isImage

Checks if a filename has an image extension (jpg, jpeg, png, gif, bmp, svg, webp).

{{ 'photo.jpg' | isImage }}     // true
{{ 'document.pdf' | isImage }}  // false

minimizeString

Truncates a string to a specified length (no ellipsis).

{{ 'Hello World' | minimizeString:5 }}  // "Hello"

msToTime

Converts milliseconds to hours or minutes.

{{ 3600000 | msToTime:'hr' }}    // "1"
{{ 60000 | msToTime:'min' }}     // "1"

msToTime:format — format is 'min' or 'hr'.


nl2br

Converts newline characters to <br/> tags. Use with [innerHTML].

<div [innerHTML]="textContent | nl2br"></div>

range

Generates an array of numbers from 1 to value, with optional start offset.

{{ 5 | range }}        // [1, 2, 3, 4, 5]
{{ 5 | range:2 }}      // [3, 4, 5]

Useful for pagination:

<button *ngFor="let page of totalPages | range">{{ page }}</button>

relativeTime

Converts a date into a relative time string.

{{ someDate | relativeTime }} // "just now", "5 minutes ago", "2 hours ago", "1 day ago", "recently"

Accepts ISO strings or Date objects.


safeHtml

Bypasses sanitization to render HTML strings as trusted HTML.

<div [innerHTML]="htmlContent | safeHtml"></div>

Dependency: DomSanitizer


safeUrl

Trusts a URL as a resource URL (for iframes, embeds, etc.).

<iframe [src]="videoUrl | safeUrl"></iframe>

Dependency: DomSanitizer


ellipsis

Strips HTML tags and truncates to a character limit (default 150), appending ... when truncated.

{{ '<p>Long HTML content here</p>' | ellipsis:50 }}

showResultsText

Generates a pagination status string.

{{ 1 | showResultsText:10:100 }}  // "Showing 1 - 10 of 100 items"
{{ 1 | showResultsText:10:0 }}    // "No items found"
{{ 1 | showResultsText:10:1 }}    // "Showing 1 item"

showResultsText:page:pageSize:totalResults


textSlice

Truncates a string to a character limit with ellipsis, optionally preserving whole words.

{{ 'The quick brown fox' | textSlice:10 }}              // "The quick..."
{{ 'The quick brown fox' | textSlice:10:'..':false }}   // "The quick.."

textSlice:limit:ellipsis:preserveWords — defaults are 100, '...', true.


titlecase

Capitalizes the first character of a string.

{{ 'hello world' | titlecase }} // "Hello world"

unique

Filters an array to unique values.

{{ [1, 2, 2, 3, 3, 3] | unique }} // [1, 2, 3]
{{ ['a', 'b', 'a', 'c'] | unique }} // ['a', 'b', 'c']

utcDate

Formats a date in UTC timezone using customizable format strings.

{{ someDate | utcDate }}                // "Jun 15, 2026" (mediumDate)
{{ someDate | utcDate:'shortDate' }}    // "15/6/26"
{{ someDate | utcDate:'fullDate' }}     // "Monday, June 15, 2026"
{{ someDate | utcDate:'yyyy-MM-dd' }}   // "2026-06-15"
{{ null | utcDate }}                    // ""

Shortcuts: 'mediumDate' (MMM d, yyyy), 'shortDate' (d/M/yy), 'fullDate' (PPPP).


valueIn

Checks if a value exists in an array.

{{ 'apple' | valueIn:['apple','banana','cherry'] }}  // true
{{ 'grape' | valueIn:['apple','banana','cherry'] }}  // false

Services

ApiService<T, TCreate>

Concrete implementation of CRUD operations using HttpClient.

import { ApiService } from '@touhidrahman/ngx-common'

interface User {
    id: string
    name: string
    email: string
}
interface CreateUserDto {
    name: string
    email: string
}

@Injectable({ providedIn: 'root' })
export class UserService extends ApiService<User, CreateUserDto> {
    constructor(http: HttpClient) {
        super('/api/users', http)
    }
}

| Method | HTTP | Endpoint | | ------------------ | ------ | --------------- | | findById(id) | GET | /{id} | | find(params) | GET | ?params | | search(term) | GET | ?search=term | | count(params) | GET | /count?params | | create(dto) | POST | / | | createMany(dtos) | POST | /many | | update(id, body) | PATCH | /{id} | | delete(id) | DELETE | /{id} | | deleteMany(ids) | DELETE | / (body: ids) |


AbstractApiService<T, TCreate>

Abstract base class for defining custom API service contracts.

import { AbstractApiService } from '@touhidrahman/ngx-common'

@Injectable()
export class CustomApiService<T, TCreate> extends AbstractApiService<
    T,
    TCreate
> {
    // Must implement all abstract methods
}

AbstractFormService<T, TCreate>

Bridges Angular Reactive Forms with an API service. Handles form building, population from API, and save logic (create/update).

import { AbstractFormService } from '@touhidrahman/ngx-common'

@Injectable()
export class UserFormService extends AbstractFormService<User, CreateUserDto> {
    buildForm(): FormGroup {
        return this.fb.group({
            name: ['', Validators.required],
            email: ['', [Validators.required, Validators.email]],
        })
    }
}
// In component
@Component({...})
export class UserEditComponent {
  constructor(private userFormService: UserFormService) {}

  ngOnInit(): void {
    this.userFormService.fillFormById$(userId).subscribe();
  }

  save(): void {
    this.userFormService.save$().subscribe(savedUser => {
      console.log('Saved:', savedUser);
    });
  }
}

| Member | Description | | ------------------------ | ------------------------------------------------------- | | form | The FormGroup instance | | valid | Whether the form is valid and touched | | getFormValue() | Returns raw form value as TCreate | | setFormValue(dto) | Populates form with data (adds id control if present) | | buildForm() | Abstract — subclass defines form structure | | fillFormById$(id) | Fetches data from API and populates form | | save$() | Calls create$ or update$ based on presence of id | | create$(resetForm) | Calls apiService.create() | | update$(id, resetForm) | Calls apiService.update() |


JwtService

Wraps @auth0/angular-jwt to decode and validate JWT tokens.

import { JwtService } from '@touhidrahman/ngx-common';

@Component({...})
export class AuthComponent {
  constructor(private jwt: JwtService) {}

  checkToken(token: string): void {
    const decoded = this.jwt.decodeToken<{ sub: string; role: string }>(token);
    const expired = this.jwt.isTokenExpired(token);
    const data = this.jwt.getUnexpiredDecoded<UserData>(token);
  }
}

LocalStorageService

SSR-safe wrapper around localStorage using @ng-web-apis/common.

import { LocalStorageService } from '@touhidrahman/ngx-common';

@Component({...})
export class SettingsComponent {
  constructor(private storage: LocalStorageService) {}

  saveTheme(theme: string): void {
    this.storage.setItem('theme', theme);
  }

  getTheme(): string | null {
    return this.storage.getItem('theme');
  }

  clearTheme(): void {
    this.storage.removeItem('theme');
  }
}

TokenSharingService

Syncs authentication tokens between browser tabs using the BroadcastChannel API.

import { TokenSharingService } from '@touhidrahman/ngx-common'

@Injectable({ providedIn: 'root' })
export class AuthService {
    constructor(private tokenSharing: TokenSharingService) {
        this.tokenSharing.init({
            accessTokenResolver: () => this.getAccessToken(),
            refreshTokenResolver: () => this.getRefreshToken(),
            accessTokenSaver: (token) => this.setAccessToken(token),
            refreshTokenSaver: (token) => this.setRefreshToken(token),
        })
    }
}

When a new tab opens, it requests tokens from existing tabs. Any tab receiving new tokens saves them via the provided saver functions.


Models

ApiResponse<T>

Generic wrapper for standardized API responses.

import { ApiResponse } from '@touhidrahman/ngx-common'

interface ApiResponse<T> {
    data: T
    meta?: Record<string, unknown>
    pagination?: {
        totalPages?: number
        totalItems?: number
        page?: number
        size?: number
    }
    error?: unknown
    message?: string
    success?: boolean
}

Used by ApiService and its consumers:

this.userService
    .find({ page: 1 })
    .subscribe((response: ApiResponse<User[]>) => {
        const users = response.data
        const totalItems = response.pagination?.totalItems
    })

LabelValuePair<T>

Generic key-value pair for dropdown options and select inputs.

import { LabelValuePair } from '@touhidrahman/ngx-common'

const options: LabelValuePair<string>[] = [
    { label: 'Active', value: 'active' },
    { label: 'Inactive', value: 'inactive' },
]
<select>
    <option *ngFor="let opt of options" [value]="opt.value">
        {{ opt.label }}
    </option>
</select>

Utility Functions

addPhonePrefix

Prepends a given prefix to a string if it is not an email and does not already have the prefix.

import { addPhonePrefix } from '@touhidrahman/ngx-common'

addPhonePrefix('1712345678', '+88') // '+881712345678'
addPhonePrefix('[email protected]', '+88') // '[email protected]'

addPhonePrefix(input, prefix)prefix is prepended only when the value is not an email and doesn't already start with prefix.


File Handling Utilities (download, getHashedFileName, getFileExtension, getFileNameFromUrl, getFileType, getMimeType)

import {
    download,
    getHashedFileName,
    getFileExtension,
    getFileNameFromUrl,
    getFileType,
    getMimeType,
} from '@touhidrahman/ngx-common'

// Trigger a file download
download('report.pdf', pdfBlob)

// Generate a unique filename
const hashed = getHashedFileName(file) // "550e8400-....pdf"

// Extract extension from a File object
const ext = getFileExtension(file) // "pdf"

// Get filename from URL
const name = getFileNameFromUrl('https://example.com/files/doc.pdf') // "doc.pdf"

// Categorize file type
const type = getFileType(file) // "image" | "document" | "audio" | "video"

// Get MIME type from path
const mime = getMimeType('photo.jpg') // "image/jpeg"

markAllControlsAsDirty

Recursively marks all controls in a form as dirty and touched.

import { markAllControlsAsDirty } from '@touhidrahman/ngx-common'

markAllControlsAsDirty([myForm])

isFutureDate

Checks if a date is in the future (compared from start of day).

import { isFutureDate } from '@touhidrahman/ngx-common'

isFutureDate('2026-12-25') // true (if today is before Dec 25, 2026)
isFutureDate('2020-01-01') // false

toHttpParams

Converts a plain object to Angular HttpParams, handling arrays by appending multiple values. Null/undefined values are skipped.

import { toHttpParams } from '@touhidrahman/ngx-common'

const params = toHttpParams({
    page: 1,
    size: 20,
    tags: ['angular', 'typescript'],
})
// URL: ?page=1&size=20&tags=angular&tags=typescript

integerValidator

Returns an Angular validator that checks if a form control value is an integer.

import { integerValidator } from '@touhidrahman/ngx-common'

this.fb.control('', [integerValidator()])
// Returns { integer: true } on validation failure

maskString

Masks the middle portion of a string, keeping visible characters at the beginning and end.

import { maskString } from '@touhidrahman/ngx-common'

maskString('1234567890', 2, 2) // "12******90"
maskString('[email protected]', 3, 4) // "hel***********mail"

maskString(input, visibleCharsHead, visibleCharsTail)


toFormData

Recursively converts an object to FormData, handling nested objects (bracket notation), arrays, Dates, Files, and Blobs.

import { toFormData } from '@touhidrahman/ngx-common'

const data = {
    name: 'John',
    avatar: fileInput.files[0],
    tags: ['dev', 'angular'],
    metadata: { version: 1 },
}

const formData = toFormData(data)
// formData entries:
//   name -> "John"
//   avatar -> File
//   tags[0] -> "dev"
//   tags[1] -> "angular"
//   metadata[version] -> "1"

Useful for file uploads with complex nested payloads.


Peer Dependencies

The following packages are required by your application when using this library:

| Package | Used By | | ------------------------- | ------------------------------------------------------------------- | | @angular/common ^21.1.0 | Core dependency | | @angular/core ^21.1.0 | Core dependency | | @angular/forms | AbstractFormService, integerValidator, markAllControlsAsDirty | | @angular/router | Params type in services | | @auth0/angular-jwt | JwtService | | @ng-web-apis/common | LocalStorageService | | date-fns | UtcDatePipe, RelativeTimePipe, isFutureDate | | date-fns-tz | UtcDatePipe | | es-toolkit | TitlecasePipe, UniquePipe, UtcDatePipe |