ngx-oneforall-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +2 -0
- package/data/docs.json +1379 -0
- package/dist/data.d.ts +28 -0
- package/dist/data.js +74 -0
- package/dist/data.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.js +247 -0
- package/dist/tools.js.map +1 -0
- package/package.json +42 -0
package/data/docs.json
ADDED
|
@@ -0,0 +1,1379 @@
|
|
|
1
|
+
{
|
|
2
|
+
"utilities": [
|
|
3
|
+
{
|
|
4
|
+
"name": "Installation",
|
|
5
|
+
"category": "getting-started",
|
|
6
|
+
"categoryTitle": "Getting Started",
|
|
7
|
+
"dirName": "installation",
|
|
8
|
+
"routePath": "installation",
|
|
9
|
+
"importPath": "ngx-oneforall/getting-started/installation",
|
|
10
|
+
"url": "https://love1024.github.io/ngx-oneforall/getting-started/installation",
|
|
11
|
+
"description": "Install the library via npm or yarn:",
|
|
12
|
+
"fullContent": "Install the library via npm or yarn:\n\n```bash\nnpm install ngx-oneforall\n```\n\nOr\n\n```bash\nyarn add ngx-oneforall\n```\n\n## Optional Dependencies\n\nFor phone validator, install:\n\n```bash\nnpm install libphonenumber-js\n```\n\n## Requirements\n\n- **Angular**: 17.1+ / 18.x / 19.x / 20.x / 21.x\n- **RxJS**: 7.x or 8.x\n\n# Usage\n\n**ngx-oneforall** is modular by design. Import only what you need from its specific path.\n\n### Example\n\n```typescript\nimport { Component } from '@angular/core';\nimport { TruncatePipe } from 'ngx-oneforall/pipes/truncate';\nimport { ClickOutsideDirective } from 'ngx-oneforall/directives/click-outside';\nimport { CacheService } from 'ngx-oneforall/services/cache';\n\n@Component({\n selector: 'app-component',\n templateUrl: 'app.component.html',\n standalone: true,\n imports: [TruncatePipe, ClickOutsideDirective],\n providers: [CacheService]\n})\nexport class AppComponent {\n}\n```\n\nSince the library is tree-shakable, only the features you actually import will be included in your final bundle.\n\n# Troubleshooting\n\nIf you run into issues:\n1. Check that your Angular version is compatible.\n2. Try clearing your `node_modules` and reinstalling.\n3. Check for any peer dependency warnings during installation."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "Introduction",
|
|
16
|
+
"category": "getting-started",
|
|
17
|
+
"categoryTitle": "Getting Started",
|
|
18
|
+
"dirName": "introduction",
|
|
19
|
+
"routePath": "introduction",
|
|
20
|
+
"importPath": "ngx-oneforall/getting-started/introduction",
|
|
21
|
+
"url": "https://love1024.github.io/ngx-oneforall/getting-started/introduction",
|
|
22
|
+
"description": "Every utility is written from scratch and optimized specifically for Angular. We prioritize memory efficiency and runtime performance rather than just wrapping existing heavy libraries. Maximum size of a utility is 3kb gzipped.",
|
|
23
|
+
"fullContent": "**ngx-oneforall** is a collection of 100+ high-quality Angular utilities designed to solve common development challenges. Instead of reinventing the wheel or managing dozens of small dependencies, you get a unified toolkit that just works.\n\n\n\n> **One For All** - A single library providing the essential blocks for modern Angular development.\n\n\n# Key Features\n\n### Performance & Efficiency\nEvery utility is written from scratch and optimized specifically for Angular. We prioritize memory efficiency and runtime performance rather than just wrapping existing heavy libraries. Maximum size of a utility is 3kb gzipped.\n\n### Modular & Tree-shakable\nImport only what you use. The library is fully tree-shakable, so adding one utility doesn't bloat your bundle with the rest of the library.\n\n### Zero Dependencies\nWe keep the dependency tree clean. **ngx-oneforall** has **NO third-party dependencies** (except `libphonenumber-js` for the phone validator). This reduces security risks, simplifies updates, and prevents version conflicts.\n\n### First-Class SSR Support\nBuilt for modern hydration. Every component and utility is designed to work seamlessly in Server-Side Rendering (SSR) environments out of the box.\n\n### 100% Test Coverage\nWe take reliability seriously. The entire library is fully covered by tests to ensure edge cases are handled and behavior remains consistent across updates.\n\n### Built for Modern Angular\nDesigned with **Signals** and **Standalone Components** in mind. This isn't a legacy port—it's built for the current and future state of Angular.\n\n---\n\n# Why Use It?\n\n### Stop Re-writing Utilities\nAvoid copy-pasting the same regex patterns, validators, and helper functions between projects. Use a standardized, tested set of utilities instead.\n\n### Focus on Business Logic\nDon't waste time maintaining generic boilerplate code. Use these proven primitives to build your actual application features faster.\n\n### Better Developer Experience\nFully typed APIs and consistent behavior make these utilities predictable and easy to work with. You get strict typing and comprehensive documentation right in your IDE.\n\n---\n\n# Available Utilities\n\n| Category | Utilities |\n|----------|-----------|\n| **Constants** | `breakpoints`, `device`, `file-extension`, `host-platforms`, `http`, `key`, `regex`, `sort-direction`, `time`, `types` |\n| **Decorators** | `cache`, `catch-error`, `debounce`, `log-execution-time`, `memoize`, `only-in-browser`, `throttle` |\n| **Directives** | `auto-focus`, `click-outside`, `click-throttle`, `hover-class`, `infinite-scroll`, `numbers-only`, `press-enter`, `repeat`, `resized`, `shortcut`, `typed-template`, `visibility-change` |\n| **Guards** | `param`, `query-param`, `unsaved-changes` |\n| **Interceptors** | `base-url`, `cache`, `correlation-id`, `encryption`, `jwt`, `performance`, `timeout` |\n| **Pipes** | `bytes`, `call`, `first-error-key`, `highlight-search`, `initials`, `pluralize`, `range`, `safe-html`, `time-ago`, `truncate` |\n| **Rxjs** | `backoff-retry`, `catch-error-with-fallback`, `data-polling`, `debug`, `live-search`, `loading-status` |\n| **Services** | `cache`, `clipboard`, `cookie`, `device`, `event`, `history`, `idle`, `jwt`, `logger`, `network-status`, `shortcut`, `storage` |\n| **Signals** | `breakpoint-matcher`, `debounced-signal`, `deep-computed`, `event-signal`, `interval-signal`, `route-param-signal`, `route-query-param-signal`, `router-event-signal`, `state-signal`, `storage-signal`, `throttled-signal`, `websocket-signal` |\n| **Utils** | `base64`, `download-link`, `find-type`, `hash`, `host-platform`, `is-key-defined`, `is-number`, `is-present`, `is-record`, `normalize-key`, `safe-await`, `safe-serialize`, `unique-component-id` |\n| **Validators** | `credit-card`, `date`, `match-field`, `max-date`, `min-date`, `min-length-trimmed`, `not-blank`, `number`, `phone`, `range`, `range-length`, `url` |\n\n---\n\n# Issues & Feature Requests\n\nFound a bug or edge case? Have an idea for a new utility? We'd love to hear from you!\n\n- **Report Issues**: If you encounter any bugs or unexpected behavior, please [open an issue](https://github.com/love1024/ngx-oneforall/issues).\n- **Feature Requests**: Have a utility in mind that would benefit the community? Submit a feature request via [GitHub Issues](https://github.com/love1024/ngx-oneforall/issues)."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "LLMs.txt",
|
|
27
|
+
"category": "getting-started",
|
|
28
|
+
"categoryTitle": "Getting Started",
|
|
29
|
+
"dirName": "llms",
|
|
30
|
+
"routePath": "llms",
|
|
31
|
+
"importPath": "ngx-oneforall/getting-started/llms",
|
|
32
|
+
"url": "https://love1024.github.io/ngx-oneforall/getting-started/llms",
|
|
33
|
+
"description": "LLM-optimized documentation endpoints for ngx-oneforall utilities.",
|
|
34
|
+
"fullContent": "LLM-optimized documentation endpoints for ngx-oneforall utilities.\n\nThe [llms.txt](https://llmstxt.org/) standard helps AI models better understand and navigate documentation. ngx-oneforall provides two files that follow this standard.\n\n---\n\n## /llms.txt\n\nThe `llms.txt` file is a structured index of all ngx-oneforall utilities. It lists every page with a title, link, and short description — making it easy for LLMs to find relevant documentation.\n\n[Open llms.txt](https://love1024.github.io/ngx-oneforall/llms.txt)\n\n---\n\n## /llms-full.txt\n\nThe `llms-full.txt` file contains the **complete documentation** for all utilities in a single file. Use this when you want an LLM to have full context about the entire library.\n\n[Open llms-full.txt](https://love1024.github.io/ngx-oneforall/llms-full.txt)\n\n---\n\n## Regenerating\n\nIf you update documentation pages and need to regenerate the LLMs files, run:\n\n```bash\nnpm run generate:llms\n```\n\nThis reads all `ng-doc.page.ts` and `index.md` files and produces both `llms.txt` and `llms-full.txt` in the `public/` directory."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "MCP Server",
|
|
38
|
+
"category": "getting-started",
|
|
39
|
+
"categoryTitle": "Getting Started",
|
|
40
|
+
"dirName": "mcp-server",
|
|
41
|
+
"routePath": "mcp-server",
|
|
42
|
+
"importPath": "ngx-oneforall/getting-started/mcp-server",
|
|
43
|
+
"url": "https://love1024.github.io/ngx-oneforall/getting-started/mcp-server",
|
|
44
|
+
"description": "Connect AI tools to ngx-oneforall documentation using the Model Context Protocol (MCP).",
|
|
45
|
+
"fullContent": "Connect AI tools to ngx-oneforall documentation using the Model Context Protocol (MCP).\n\nThe MCP server gives AI assistants like Claude, Cursor, Windsurf, and VS Code Copilot **native knowledge** of all ngx-oneforall utilities — including correct import paths, API references, and usage examples.\n\n---\n\n## What is MCP?\n\nMCP (Model Context Protocol) is a standard that lets AI tools connect to external knowledge sources. Instead of the AI guessing about your library, it can **look up real documentation** in real-time.\n\nWithout MCP, an AI might hallucinate:\n```typescript\n// ❌ Wrong import path\nimport { Draggable } from 'ngx-oneforall';\n```\n\nWith MCP, the AI looks up the correct import:\n```typescript\n// ✅ Correct import path\nimport { DraggableDirective } from 'ngx-oneforall/directives/draggable';\n```\n\n---\n\n## Installation\n\nInstall the MCP server globally or use it via `npx`:\n\n```bash\nnpx ngx-oneforall-mcp\n```\n\nNo additional dependencies are required in your Angular project.\n\n---\n\n## Setup by AI Tool\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n \"mcpServers\": {\n \"ngx-oneforall\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"ngx-oneforall-mcp\"]\n }\n }\n}\n```\n\nRestart Claude Desktop after saving.\n\n### Cursor\n\nEdit `.cursor/mcp.json` in your project root:\n\n```json\n{\n \"mcpServers\": {\n \"ngx-oneforall\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"ngx-oneforall-mcp\"]\n }\n }\n}\n```\n\n### Windsurf\n\nEdit `~/.codeium/windsurf/mcp_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"ngx-oneforall\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"ngx-oneforall-mcp\"]\n }\n }\n}\n```\n\n### VS Code (GitHub Copilot)\n\nEdit `.vscode/mcp.json` in your project root:\n\n```json\n{\n \"servers\": {\n \"ngx-oneforall\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"ngx-oneforall-mcp\"]\n }\n }\n}\n```\n\n---\n\n## Available Tools\n\nOnce configured, your AI assistant can use these tools automatically:\n\n| Tool | What it does |\n|------|-------------|\n| `get_utility_docs` | Returns full documentation for any utility by name |\n| `search_utilities` | Searches utilities by keyword across names, descriptions, and docs |\n| `list_utilities` | Lists all utilities, optionally filtered by category |\n| `get_import_path` | Returns the exact TypeScript import statement for a utility |\n\n---\n\n## Example Usage\n\nAfter setup, just ask your AI assistant naturally:\n\n- *\"How do I use the draggable directive from ngx-oneforall?\"*\n- *\"What validators does ngx-oneforall provide?\"*\n- *\"Show me the import path for the time-ago pipe\"*\n- *\"What signals are available for reactive routing?\"*\n\nThe AI will automatically call the MCP server to look up accurate documentation and provide correct answers.\n\n---\n\n## Resources\n\nThe MCP server also exposes resources that AI tools can read directly:\n\n| Resource | URI |\n|----------|-----|\n| Structured index | `ngx-oneforall://llms.txt` |\n| Per-utility docs | `ngx-oneforall://docs/{category}/{utility}` |"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "Breakpoints",
|
|
49
|
+
"category": "constants",
|
|
50
|
+
"categoryTitle": "Constants",
|
|
51
|
+
"dirName": "breakpoints",
|
|
52
|
+
"routePath": "breakpoints",
|
|
53
|
+
"importPath": "ngx-oneforall/constants/breakpoints",
|
|
54
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/breakpoints",
|
|
55
|
+
"description": "The ngx-oneforall/constants package provides a set of constants for responsive design breakpoints, including their names, numeric values, and CSS media query strings.",
|
|
56
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a set of constants for responsive design breakpoints, including their names, numeric values, and CSS media query strings.\n\n## Usage\n\nImport the constants to handle responsive logic in your components or services.\n\n```typescript\nimport { BREAKPOINT, BREAKPOINT_QUERY } from 'ngx-oneforall/constants';\n\n// Example: Using a media query in a component\nconst isMobileQuery = BREAKPOINT_QUERY[BREAKPOINT.XS];\n\n// Example: Comparing against a breakpoint value\nif (window.innerWidth >= BREAKPOINT_VALUE.MD) {\n // Logic for tablet and above\n}\n```\n\n## BREAKPOINT\n\nThe `BREAKPOINT` constant defines the names of the support breakpoints.\n\n| Name | Value |\n| :--- | :--- |\n| **XS** | `'xs'` |\n| **SM** | `'sm'` |\n| **MD** | `'md'` |\n| **LG** | `'lg'` |\n| **XL** | `'xl'` |\n| **XXL** | `'xxl'` |\n| **SM_ONLY** | `'smOnly'` |\n| **MD_ONLY** | `'mdOnly'` |\n| **LG_ONLY** | `'lgOnly'` |\n| **XL_ONLY** | `'xlOnly'` |\n\n## BREAKPOINT_VALUE\n\nNumeric pixel values for each breakpoint threshold.\n\n| Name | Value (px) |\n| :--- | :--- |\n| **XS** | `0` |\n| **SM** | `576` |\n| **MD** | `768` |\n| **LG** | `992` |\n| **XL** | `1200` |\n| **XXL** | `1400` |\n\n## BREAKPOINT_QUERY\n\nStandardized CSS media query strings for each breakpoint.\n\n| Breakpoint | Media Query |\n| :--- | :--- |\n| **XS** | `(max-width: 575.98px)` |\n| **SM** | `(min-width: 576px)` |\n| **MD** | `(min-width: 768px)` |\n| **LG** | `(min-width: 992px)` |\n| **XL** | `(min-width: 1200px)` |\n| **XXL** | `(min-width: 1400px)` |\n| **SM_ONLY**| `(min-width: 576px) and (max-width: 767.98px)` |\n| **MD_ONLY**| `(min-width: 768px) and (max-width: 991.98px)` |\n| **LG_ONLY**| `(min-width: 992px) and (max-width: 1199.98px)` |\n| **XL_ONLY**| `(min-width: 1200px) and (max-width: 1399.98px)` |"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "Device",
|
|
60
|
+
"category": "constants",
|
|
61
|
+
"categoryTitle": "Constants",
|
|
62
|
+
"dirName": "device",
|
|
63
|
+
"routePath": "device",
|
|
64
|
+
"importPath": "ngx-oneforall/constants/device",
|
|
65
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/device",
|
|
66
|
+
"description": "The ngx-oneforall/constants package provides a constant for categorizing devices by type, which is useful for conditional logic based on the platform.",
|
|
67
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a constant for categorizing devices by type, which is useful for conditional logic based on the platform.\n\n## Usage\n\nImport the `DEVICE_TYPE` constant to use in your components or services.\n\n```typescript\nimport { DEVICE_TYPE } from 'ngx-oneforall/constants';\n\n// Example: Handling logic based on device type\nif (currentDevice() === DEVICE_TYPE.Mobile) {\n // Mobile specific logic\n}\n```\n\n## DEVICE_TYPE\n\n| Name | Value |\n| :--- | :--- |\n| **Mobile** | `'mobile'` |\n| **Tablet** | `'tablet'` |\n| **Desktop** | `'desktop'` |"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "File Extension",
|
|
71
|
+
"category": "constants",
|
|
72
|
+
"categoryTitle": "Constants",
|
|
73
|
+
"dirName": "file-extension",
|
|
74
|
+
"routePath": "file-extension",
|
|
75
|
+
"importPath": "ngx-oneforall/constants/file-extension",
|
|
76
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/file-extension",
|
|
77
|
+
"description": "The ngx-oneforall/constants package provides a comprehensive set of common file extensions. These constants are useful for file type validation, filtering, and handling file uploads.",
|
|
78
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a comprehensive set of common file extensions. These constants are useful for file type validation, filtering, and handling file uploads.\n\n## Usage\n\nImport the `FILE_EXTENSION` constant to use in your file handling logic.\n\n```typescript\nimport { FILE_EXTENSION } from 'ngx-oneforall/constants';\n\n// Example: Checking if a file is an image\nconst isImage = [\n FILE_EXTENSION.PNG,\n FILE_EXTENSION.JPG,\n FILE_EXTENSION.JPEG,\n FILE_EXTENSION.GIF,\n FILE_EXTENSION.WEBP\n].includes(fileExtension.toLowerCase());\n\n// Example: Restricting file upload to documents\nconst acceptedDocs = `${FILE_EXTENSION.PDF},${FILE_EXTENSION.DOCX},${FILE_EXTENSION.XLSX}`;\n```\n\n## FILE_EXTENSION\n\n### Images\n\n| Name | Value |\n| :--- | :--- |\n| **PNG** | `'png'` |\n| **JPG** | `'jpg'` |\n| **JPEG** | `'jpeg'` |\n| **GIF** | `'gif'` |\n| **WEBP** | `'webp'` |\n| **SVG** | `'svg'` |\n\n### Documents\n\n| Name | Value |\n| :--- | :--- |\n| **PDF** | `'pdf'` |\n| **DOC** | `'doc'` |\n| **DOCX** | `'docx'` |\n| **XLS** | `'xls'` |\n| **XLSX** | `'xlsx'` |\n| **CSV** | `'csv'` |\n| **TXT** | `'txt'` |\n| **RTF** | `'rtf'` |\n\n### Presentations\n\n| Name | Value |\n| :--- | :--- |\n| **PPT** | `'ppt'` |\n| **PPTX** | `'pptx'` |\n\n### Archives\n\n| Name | Value |\n| :--- | :--- |\n| **ZIP** | `'zip'` |\n| **RAR** | `'rar'` |\n| **TAR** | `'tar'` |\n| **GZ** | `'gz'` |\n| **_7Z** | `'7z'` |\n\n### Audio\n\n| Name | Value |\n| :--- | :--- |\n| **MP3** | `'mp3'` |\n| **WAV** | `'wav'` |\n| **AAC** | `'aac'` |\n| **FLAC** | `'flac'` |\n| **OGG** | `'ogg'` |\n\n### Video\n\n| Name | Value |\n| :--- | :--- |\n| **MP4** | `'mp4'` |\n| **WEBM** | `'webm'` |\n| **MKV** | `'mkv'` |\n| **AVI** | `'avi'` |\n| **MOV** | `'mov'` |"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "Host Platforms",
|
|
82
|
+
"category": "constants",
|
|
83
|
+
"categoryTitle": "Constants",
|
|
84
|
+
"dirName": "host-platforms",
|
|
85
|
+
"routePath": "host-platforms",
|
|
86
|
+
"importPath": "ngx-oneforall/constants/host-platforms",
|
|
87
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/host-platforms",
|
|
88
|
+
"description": "The HostPlatform enum defines the supported host platforms (operating systems) that can be detected by the getHostPlatform utility.",
|
|
89
|
+
"fullContent": "---\nkeyword: HostPlatformsPage\n---\n\nThe `HostPlatform` enum defines the supported host platforms (operating systems) that can be detected by the `getHostPlatform` utility.\n\n## Usage\n\nImport `HostPlatform` from `ngx-oneforall`:\n\n```typescript\nimport {HostPlatform} from 'ngx-oneforall/constants';\n\n// Usage with getHostPlatform\nconst platform = getHostPlatform();\n\nif (platform === HostPlatform.MAC) {\n // macOS specific logic\n}\n```\n\n## Enum Values\n\n| Member | Value | Description |\n|--------|-------|-------------|\n| `MAC` | `'MAC'` | macOS |\n| `IOS` | `'IOS'` | iOS (iPhone, iPad, iPod) |\n| `WINDOWS` | `'WINDOWS'` | Windows |\n| `WINDOWS_PHONE` | `'WINDOWS_PHONE'` | Windows Phone |\n| `ANDROID` | `'ANDROID'` | Android |\n| `LINUX` | `'LINUX'` | Linux |\n| `UNKNOWN` | `'UNKNOWN'` | Unknown platform |"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "HTTP",
|
|
93
|
+
"category": "constants",
|
|
94
|
+
"categoryTitle": "Constants",
|
|
95
|
+
"dirName": "http",
|
|
96
|
+
"routePath": "http",
|
|
97
|
+
"importPath": "ngx-oneforall/constants/http",
|
|
98
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/http",
|
|
99
|
+
"description": "The ngx-oneforall/constants package provides sets of constants for common HTTP methods and headers. Using these constants helps prevent typos and improves code maintainability.",
|
|
100
|
+
"fullContent": "The `ngx-oneforall/constants` package provides sets of constants for common HTTP methods and headers. Using these constants helps prevent typos and improves code maintainability.\n\n## Usage\n\nImport the constants from the constants package and use them in your HTTP requests or interceptors.\n\n```typescript\nimport { HTTP_METHOD, HTTP_HEADER } from 'ngx-oneforall/constants';\n\n// In an interceptor or service\nconst headers = new HttpHeaders({\n [HTTP_HEADER.ContentType]: 'application/json',\n [HTTP_HEADER.Authorization]: `Bearer ${token}`\n});\n\nthis.http.request(HTTP_METHOD.POST, url, { headers, body });\n```\n\n## HTTP Methods\n\nThe `HTTP_METHOD` constant includes standard HTTP verbs.\n\n| Name | Value |\n| :--- | :--- |\n| **GET** | `'GET'` |\n| **POST** | `'POST'` |\n| **PUT** | `'PUT'` |\n| **PATCH** | `'PATCH'` |\n| **DELETE** | `'DELETE'` |\n| **OPTIONS** | `'OPTIONS'` |\n| **HEAD** | `'HEAD'` |\n\n## HTTP Headers\n\nThe `HTTP_HEADER` constant includes commonly used HTTP header names.\n\n| Name | Value |\n| :--- | :--- |\n| **Authorization** | `'Authorization'` |\n| **ContentType** | `'Content-Type'` |\n| **Accept** | `'Accept'` |\n| **CacheControl** | `'Cache-Control'` |\n| **IfNoneMatch** | `'If-None-Match'` |"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "Keys",
|
|
104
|
+
"category": "constants",
|
|
105
|
+
"categoryTitle": "Constants",
|
|
106
|
+
"dirName": "keys",
|
|
107
|
+
"routePath": "keys",
|
|
108
|
+
"importPath": "ngx-oneforall/constants/keys",
|
|
109
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/keys",
|
|
110
|
+
"description": "The ngx-oneforall/constants package provides sets of constants for keyboard keys and their corresponding numeric codes. These are useful for handling keyboard events in a type-safe way.",
|
|
111
|
+
"fullContent": "The `ngx-oneforall/constants` package provides sets of constants for keyboard keys and their corresponding numeric codes. These are useful for handling keyboard events in a type-safe way.\n\n## Usage\n\nYou can use these constants when listening to keyboard events to avoid hardcoding strings or magic numbers.\n\n```typescript\nimport { Key, KeyCode } from 'ngx-oneforall/constants';\n\n// Using Key strings\nif (event.key === Key.Enter) {\n // Handle enter key\n}\n\n// Using KeyCodes\nif (event.keyCode === KeyCode.Enter) {\n // Handle enter key code\n}\n```\n\n## Key Strings\n\nThe `Key` constant contains standard string values for keys, typically matching `event.key`.\n\n| Name | Value |\n| :--- | :--- |\n| **Backspace** | `'Backspace'` |\n| **Tab** | `'Tab'` |\n| **Enter** | `'Enter'` |\n| **Shift** | `'Shift'` |\n| **Control** | `'Control'` |\n| **Alt** | `'Alt'` |\n| **Pause** | `'Pause'` |\n| **CapsLock** | `'CapsLock'` |\n| **Escape** | `'Escape'` |\n| **Space** | `' '` |\n| **PageUp** | `'PageUp'` |\n| **PageDown** | `'PageDown'` |\n| **End** | `'End'` |\n| **Home** | `'Home'` |\n| **ArrowLeft** | `'ArrowLeft'` |\n| **ArrowUp** | `'ArrowUp'` |\n| **ArrowRight** | `'ArrowRight'` |\n| **ArrowDown** | `'ArrowDown'` |\n| **Insert** | `'Insert'` |\n| **Delete** | `'Delete'` |\n\n### Numbers & Letters\n\nIncludes digits `0-9` (value matches digit) and letters `a-z` (lowercase).\n\n### Function Keys\n\nIncludes `F1` through `F12`.\n\n---\n\n## Key Codes\n\nThe `KeyCode` constant contains the numeric values for keys, typically matching `event.keyCode`.\n\n| Name | Code |\n| :--- | :--- |\n| **Backspace** | `8` |\n| **Tab** | `9` |\n| **Enter** | `13` |\n| **Shift** | `16` |\n| **Control** | `17` |\n| **Alt** | `18` |\n| **Pause** | `19` |\n| **CapsLock** | `20` |\n| **Escape** | `27` |\n| **Space** | `32` |\n| **PageUp** | `33` |\n| **PageDown** | `34` |\n| **End** | `35` |\n| **Home** | `36` |\n| **ArrowLeft** | `37` |\n| **ArrowUp** | `38` |\n| **ArrowRight** | `39` |\n| **ArrowDown** | `40` |\n| **Insert** | `45` |\n| **Delete** | `46` |\n\n### Numbers & Letters\n\n- **Digits (0-9)**: Codes `48` to `57`.\n- **Letters (A-Z)**: Codes `65` to `90`.\n\n### Function Keys\n\n- **F1-F12**: Codes `112` to `123`."
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "Regex",
|
|
115
|
+
"category": "constants",
|
|
116
|
+
"categoryTitle": "Constants",
|
|
117
|
+
"dirName": "regex",
|
|
118
|
+
"routePath": "regex",
|
|
119
|
+
"importPath": "ngx-oneforall/constants/regex",
|
|
120
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/regex",
|
|
121
|
+
"description": "The ngx-oneforall/constants package provides a set of common regular expressions for data validation. These constants help you maintain consistency and avoid duplicate regex definitions across your application.",
|
|
122
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a set of common regular expressions for data validation. These constants help you maintain consistency and avoid duplicate regex definitions across your application.\n\n## Usage\n\nImport the `REGEX` constant to use in your validators or logic.\n\n```typescript\nimport { REGEX } from 'ngx-oneforall/constants';\n\n// Example: Using regex for manual validation\nconst value = '12345';\nconst isNumeric = REGEX.Numeric.test(value);\n\n// Example: Using in an Angular FormControl validator (Pattern validator)\nconst control = new FormControl('', [Validators.pattern(REGEX.AlphaNumeric)]);\n```\n\n## REGEX\n\n### Numeric\n\n| Name | Regex | Description |\n| :--- | :--- | :--- |\n| **Numeric** | `/^\\d+$/` | Matches one or more digits. |\n| **Integer** | `/^-?\\d+$/` | Matches positive or negative integers. |\n| **Decimal** | `/^-?\\d+(\\.\\d+)?$/` | Matches positive or negative decimal numbers. |\n| **PositiveInteger** | `/^\\d+$/` | Matches positive integers. |\n| **NegativeInteger** | `/^-\\d+$/` | Matches negative integers. |\n\n### Alphabetic\n\n| Name | Regex | Description |\n| :--- | :--- | :--- |\n| **Alpha** | `/^[a-zA-Z]+$/` | Matches alphabetic characters (case-insensitive). |\n| **AlphaLower** | `/^[a-z]+$/` | Matches lowercase alphabetic characters. |\n| **AlphaUpper** | `/^[A-Z]+$/` | Matches uppercase alphabetic characters. |\n| **AlphaNumeric** | `/^[a-zA-Z0-9]+$/` | Matches alphabetic and numeric characters. |"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "Sort Direction",
|
|
126
|
+
"category": "constants",
|
|
127
|
+
"categoryTitle": "Constants",
|
|
128
|
+
"dirName": "sort-direction",
|
|
129
|
+
"routePath": "sort-direction",
|
|
130
|
+
"importPath": "ngx-oneforall/constants/sort-direction",
|
|
131
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/sort-direction",
|
|
132
|
+
"description": "The ngx-oneforall/constants package provides a constant for sort directions, helping you maintain consistency across your sorting logic.",
|
|
133
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a constant for sort directions, helping you maintain consistency across your sorting logic.\n\n## Usage\n\nImport the `SORT_DIRECTION` constant to use in your sorting functions or components.\n\n```typescript\nimport { SORT_DIRECTION } from 'ngx-oneforall/constants';\n\n// Example: Handling sort change\nfunction onSortChange(direction: 'asc' | 'desc') {\n if (direction === SORT_DIRECTION.Asc) {\n // Handle ascending sort\n } else {\n // Handle descending sort\n }\n}\n```\n\n## SORT_DIRECTION\n\n| Name | Value |\n| :--- | :--- |\n| **Asc** | `'asc'` |\n| **Desc** | `'desc'` |"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "Time",
|
|
137
|
+
"category": "constants",
|
|
138
|
+
"categoryTitle": "Constants",
|
|
139
|
+
"dirName": "time",
|
|
140
|
+
"routePath": "time",
|
|
141
|
+
"importPath": "ngx-oneforall/constants/time",
|
|
142
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/time",
|
|
143
|
+
"description": "The ngx-oneforall/constants package provides a set of common time duration constants in milliseconds. These are useful for timeouts, intervals, and date manipulations.",
|
|
144
|
+
"fullContent": "The `ngx-oneforall/constants` package provides a set of common time duration constants in milliseconds. These are useful for timeouts, intervals, and date manipulations.\n\n## Usage\n\nImport the `TIME` constant to use in your timers or logic.\n\n```typescript\nimport { TIME } from 'ngx-oneforall/constants';\n\n// Set an interval of one minute\nsetInterval(() => {\n console.log('One minute passed');\n}, TIME.Minute);\n\n// Calculate three hours in ms\nconst threeHours = 3 * TIME.Hour;\n```\n\n## TIME\n\nAll values are represented in **milliseconds**.\n\n| Name | Milliseconds | Value |\n| :--- | :--- | :--- |\n| **Second** | `1,000` | `1000` |\n| **Minute** | `60,000` | `60_000` |\n| **Hour** | `3,600,000` | `3_600_000` |\n| **Day** | `86,400,000` | `86_400_000` |\n| **Week** | `604,800,000` | `604_800_000` |"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "Types",
|
|
148
|
+
"category": "constants",
|
|
149
|
+
"categoryTitle": "Constants",
|
|
150
|
+
"dirName": "types",
|
|
151
|
+
"routePath": "types",
|
|
152
|
+
"importPath": "ngx-oneforall/constants/types",
|
|
153
|
+
"url": "https://love1024.github.io/ngx-oneforall/constants/types",
|
|
154
|
+
"description": "The Types enum above provides a comprehensive list of possible JavaScript and TypeScript types, including primitives like String and Number, complex structures like Map and Set, as well as iterators and typed arrays. Using such enums can help with type checking, validation, and implementing utility functions that depend on type information.",
|
|
155
|
+
"fullContent": "=\nThe `Types` enum above provides a comprehensive list of possible JavaScript and TypeScript types, including primitives like `String` and `Number`, complex structures like `Map` and `Set`, as well as iterators and typed arrays. Using such enums can help with type checking, validation, and implementing utility functions that depend on type information.\n``` typescript\nexport enum Types {\n Undefined = 'UNDEFINED',\n Null = 'NULL',\n Boolean = 'BOOLEAN',\n String = 'STRING',\n Number = 'NUMBER',\n Symbol = 'SYMBOL',\n Function = 'FUNCTION',\n Array = 'ARRAY',\n GeneratorFunction = 'GENERATOR_FUNCTION\"',\n Unknown = 'UNKNOWN',\n Map = 'MAP',\n WeakMap = 'WEAK_MAP',\n Set = 'SET',\n WeakSet = 'WeakSet',\n Int8Array = 'INT8ARRAY',\n Uint8Array = 'UINT8ARRAY',\n Uint8ClampedArray = 'UINT8CLAMPEDARRAY',\n Int16Array = 'INT16ARRAY',\n Uint16Array = 'UINT16ARRAY',\n Int32Array = 'INT32ARRAY',\n Uint32Array = 'UINT32ARRAY',\n Float32Array = 'FLOAT32ARRAY',\n Float64Array = 'FLOAT64ARRAY',\n GeneratorObject = 'GENERATOR_OBJECT',\n Object = 'OBJECT',\n MapIterator = 'MAP_ITERATOR',\n SetIterator = 'SET_ITERATOR',\n StringIterator = 'STRING_ITERATOR',\n ArrayIterator = 'ARRAY_ITERATOR',\n}\n```"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "Cache",
|
|
159
|
+
"category": "decorators",
|
|
160
|
+
"categoryTitle": "Decorators",
|
|
161
|
+
"dirName": "cache",
|
|
162
|
+
"routePath": "cache",
|
|
163
|
+
"importPath": "ngx-oneforall/decorators/cache",
|
|
164
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/cache",
|
|
165
|
+
"description": "The Cache decorator caches Observable method results with configurable storage, TTL, and versioning.",
|
|
166
|
+
"fullContent": "The `Cache` decorator caches Observable method results with configurable storage, TTL, and versioning.\n\n> **Note**\n> **When to use:** Use `@Cache` for Observable methods. For sync or Promise methods, use [`@memoize`](/decorators/memoize) instead.\n\n### Parameters\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `storage` | `'memory' \\| 'local' \\| 'session'` | `'memory'` | Storage backend |\n| `storageKey` | `string` | `'CACHE_DECORATOR'` | Storage key for cache data |\n| `ttl` | `number \\| null` | `null` | Time-to-live in ms (`null` = no expiration) |\n| `itemCacheKey` | `string` | Auto | Custom cache key for method |\n| `maxItems` | `number \\| null` | `null` | Max cached items (`null` = unlimited) |\n| `version` | `string` | — | Cache version (change clears cache) |\n| `cacheKeyMatcher` | `Function` | Deep compare | Custom param comparison |\n| `cacheKeySelector` | `Function` | All params | Select params for cache key |\n\n### Features\n\n- **Multi-storage**: Memory, localStorage, sessionStorage\n- **TTL expiration**: Auto-invalidate stale entries\n- **Version control**: Clear cache on version change\n- **Request deduplication**: Concurrent calls share same Observable\n- **LRU eviction**: Limit cache size with `maxItems`\n- **Error handling**: Failed requests are NOT cached\n\n### Basic Usage\n\n```typescript\n@Injectable({ providedIn: 'root' })\nexport class UserService {\n @Cache({ ttl: 60000 })\n getUser(id: number): Observable<User> {\n return this.http.get<User>(`/api/users/${id}`);\n }\n}\n```\n\n### With Storage & Max Items\n\n```typescript\n@Cache({ storage: 'local', maxItems: 10, ttl: 300000 })\nsearchUsers(query: string): Observable<User[]> {\n return this.http.get<User[]>(`/api/users?q=${query}`);\n}\n```\n\n### Version Control\n\n```typescript\n@Cache({ version: '2.0.0', storage: 'session' })\ngetConfig(): Observable<Config> {\n return this.http.get<Config>('/api/config');\n}\n```\n\nChanging `version` clears all cached data for this method.\n\n### Manual Cache Clearing\n\nYou can manually clear the cache for a specific method by calling `clearCache()` on the decorated method.\nYou will need to cast the method to `CachedMethod<T>`.\n\n```typescript\nimport { CachedMethod } from 'ngx-oneforall/decorators/cache';\n\n// ...\nrefreshData() {\n (this.getData as unknown as CachedMethod).clearCache();\n // Next call to this.getData() will hit the server\n}\n```\n\n### Custom Cache Key\n\n```typescript\n// Only use first param as cache key\n@Cache({\n cacheKeySelector: (params) => params[0],\n})\ngetData(id: number, timestamp: Date): Observable<Data> {\n return this.http.get<Data>(`/api/data/${id}`);\n}\n```\n\n### Live Demonstration"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "Catch Error",
|
|
170
|
+
"category": "decorators",
|
|
171
|
+
"categoryTitle": "Decorators",
|
|
172
|
+
"dirName": "catch-error",
|
|
173
|
+
"routePath": "catch-error",
|
|
174
|
+
"importPath": "ngx-oneforall/decorators/catch-error",
|
|
175
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/catch-error",
|
|
176
|
+
"description": "The CatchError decorator catches errors and provides fallback behavior for sync, Promise, and Observable methods.",
|
|
177
|
+
"fullContent": "The `CatchError` decorator catches errors and provides fallback behavior for sync, Promise, and Observable methods.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `fallback` | `unknown \\| ((error) => unknown)` | `undefined` | Value or function to return on error |\n| `logError` | `boolean` | `true` | Log errors to console |\n\n### Features\n\n- **Sync methods**: Wraps in try-catch\n- **Promises**: Adds `.catch()` handler\n- **Observables**: Pipes through `catchError`\n- **Dynamic fallback**: Function receives error, can return dynamic value\n- **Re-throw**: If `fallback` is undefined, error is re-thrown\n\n### Basic Usage\n\n```typescript\n// Static fallback value\n@CatchError([])\ngetUsers(): Observable<User[]> {\n return this.http.get<User[]>('/api/users');\n}\n```\n\n### Dynamic Fallback\n\n```typescript\n// Fallback function receives error\n@CatchError((err) => ({ error: true, message: err.message }))\nasync fetchData(): Promise<Data> {\n return await this.api.getData();\n}\n```\n\n### Observable Fallback\n\n```typescript\n// Return Observable from fallback\n@CatchError((err) => of({ fallback: true }))\ngetData(): Observable<any> {\n return throwError(() => new Error('fail'));\n}\n```\n\n### Silent Errors\n\n```typescript\n// Disable console logging\n@CatchError(null, false)\nsilentFetch(): Observable<any> { ... }\n```\n\n### Live Demonstration"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"name": "Debounce",
|
|
181
|
+
"category": "decorators",
|
|
182
|
+
"categoryTitle": "Decorators",
|
|
183
|
+
"dirName": "debounce",
|
|
184
|
+
"routePath": "debounce",
|
|
185
|
+
"importPath": "ngx-oneforall/decorators/debounce",
|
|
186
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/debounce",
|
|
187
|
+
"description": "The debounce decorator delays method execution until a specified time has passed since the last call. Supports leading/trailing edge execution.",
|
|
188
|
+
"fullContent": "The `debounce` decorator delays method execution until a specified time has passed since the last call. Supports leading/trailing edge execution.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `options` | `number \\| DebounceOptions` | `300` | Delay in ms or options object |\n| `options.delay` | `number` | `300` | Delay in milliseconds |\n| `options.leading` | `boolean` | `false` | Execute on first call (leading edge) |\n\n### Features\n\n- **Trailing edge** (default): Executes after delay elapses\n- **Leading edge**: Executes immediately on first call\n- **Return value caching**: Returns last result from original method\n- **Instance isolation**: Each instance has its own debounced state\n\n### Basic Usage\n\n```typescript\n@debounce(300)\nonInputChange(event: Event): void {\n this.value = (event.target as HTMLInputElement).value;\n}\n```\n\n### Leading Edge\n\nExecute immediately on first call, then debounce:\n\n```typescript\n@debounce({ delay: 300, leading: true })\nonButtonClick(): void {\n this.performAction();\n}\n```\n\n### With Options Object\n\n```typescript\n@debounce({ delay: 500, leading: false })\nonScroll(): void {\n this.updateScrollPosition();\n}\n```\n\n### Comparison\n\n| Mode | First Call | During Delay | After Delay |\n|------|------------|--------------|-------------|\n| `leading: false` | Schedules | Resets timer | Executes |\n| `leading: true` | Executes | Resets timer | Resets state |\n\n### Live Demonstration"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"name": "Log Execution Time",
|
|
192
|
+
"category": "decorators",
|
|
193
|
+
"categoryTitle": "Decorators",
|
|
194
|
+
"dirName": "log-execution-time",
|
|
195
|
+
"routePath": "log-execution-time",
|
|
196
|
+
"importPath": "ngx-oneforall/decorators/log-execution-time",
|
|
197
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/log-execution-time",
|
|
198
|
+
"description": "The LogExecutionTime decorator logs method execution time. Works with sync, Promise, and Observable methods.",
|
|
199
|
+
"fullContent": "The `LogExecutionTime` decorator logs method execution time. Works with sync, Promise, and Observable methods.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `label` | `string` | Method name | Custom label for log message |\n\n### Output Format\n\n```\n[label] executed in X.XX ms\n```\n\n### Features\n\n- **Sync methods**: Logs after return\n- **Promises**: Logs after resolution/rejection\n- **Observables**: Logs after completion via `finalize()`\n- **Global disable**: Turn off logging for production\n\n### Basic Usage\n\n```typescript\n@LogExecutionTime()\ngetData(): Observable<Data> {\n return this.http.get<Data>('/api/data');\n}\n// Console: [getData] executed in 123.45 ms\n```\n\n### Custom Label\n\n```typescript\n@LogExecutionTime('FetchUsers')\nasync getUsers(): Promise<User[]> {\n return await this.api.fetchUsers();\n}\n// Console: [FetchUsers] executed in 456.78 ms\n```\n\n### Disable in Production\n\n```typescript\nimport { disableLogExecutionTime } from 'ngx-oneforall/decorators/log-execution-time';\n\n// main.ts\nif (environment.production) {\n disableLogExecutionTime();\n}\n```\n\n### Helper Functions\n\n| Function | Description |\n|----------|-------------|\n| `disableLogExecutionTime()` | Disables logging globally |\n| `enableLogExecutionTime()` | Re-enables logging |\n| `isLogExecutionTimeEnabled()` | Returns current enabled state |\n\n### Live Demonstration"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "Memoize",
|
|
203
|
+
"category": "decorators",
|
|
204
|
+
"categoryTitle": "Decorators",
|
|
205
|
+
"dirName": "memoize",
|
|
206
|
+
"routePath": "memoize",
|
|
207
|
+
"importPath": "ngx-oneforall/decorators/memoize",
|
|
208
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/memoize",
|
|
209
|
+
"description": "The @memoize decorator caches method results based on arguments. Works with sync and Promise methods.",
|
|
210
|
+
"fullContent": "The `@memoize` decorator caches method results based on arguments. Works with sync and Promise methods.\n\n> **Note**\n> **When to use:** Use `@memoize` for sync or Promise methods. For Observable methods, use [`@Cache`](/decorators/cache) instead.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `resolver` | `(...args) => string` | `safeSerialize` | Custom cache key function |\n| `maxSize` | `number` | `undefined` | Max cache entries (LRU eviction) |\n\n### Features\n\n- **Sync and Promise support** - Caches both method returns and promise resolutions\n- **Per-instance caching** - No shared state between instances\n- **Custom key resolver** - Use object IDs instead of full serialization\n- **Max cache size** - Limit cache with LRU eviction\n\n### Basic Usage\n\n```typescript\nimport { memoize } from 'ngx-oneforall/decorators/memoize';\n\n@memoize()\nfactorial(n: number): number {\n if (n <= 1) return 1;\n return n * this.factorial(n - 1);\n}\n```\n\n### Async Support\n\n```typescript\n@memoize()\nfetchUser(id: string): Promise<User> {\n return this.http.get<User>(`/api/users/${id}`).toPromise();\n}\n// Second call returns cached promise\n```\n\n### Custom Resolver\n\n```typescript\n@memoize({ resolver: (user: User) => user.id })\nprocessUser(user: User) {\n // Uses user.id as cache key instead of full serialization\n}\n```\n\n### Max Cache Size\n\n```typescript\n@memoize({ maxSize: 100 })\ncompute(input: string): number {\n // Cache limited to 100 entries, oldest evicted first\n}\n```\n\n### Best Practices\n\n- **Pure methods only** - Don't use on methods with side effects\n- **Use maxSize for large caches** - Prevent memory leaks\n- **Use resolver for objects with IDs** - Faster than serialization\n\n### Live Demonstration"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"name": "Only In Browser",
|
|
214
|
+
"category": "decorators",
|
|
215
|
+
"categoryTitle": "Decorators",
|
|
216
|
+
"dirName": "only-in-browser",
|
|
217
|
+
"routePath": "only-in-browser",
|
|
218
|
+
"importPath": "ngx-oneforall/decorators/only-in-browser",
|
|
219
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/only-in-browser",
|
|
220
|
+
"description": "The OnlyInBrowser decorator ensures methods only execute in browser environment, not during SSR.",
|
|
221
|
+
"fullContent": "The `OnlyInBrowser` decorator ensures methods only execute in browser environment, not during SSR.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `fallback` | `T` | `undefined` | Value to return when not in browser |\n\n### Features\n\n- **SSR-safe** - Prevents browser-specific code from running on server\n- **Fallback support** - Return custom value during SSR\n- **Zero config** - Works without options for void methods\n\n### Basic Usage\n\n```typescript\nimport { OnlyInBrowser } from 'ngx-oneforall/decorators/only-in-browser';\n\n@OnlyInBrowser()\ninitLocalStorage(): void {\n localStorage.setItem('initialized', 'true');\n}\n```\n\n### With Fallback\n\n```typescript\n@OnlyInBrowser({ fallback: [] })\ngetFromStorage(): string[] {\n return JSON.parse(localStorage.getItem('items') || '[]');\n}\n// Returns [] during SSR instead of undefined\n```\n\n### Observable Fallback\n\n```typescript\n@OnlyInBrowser({ fallback: of([]) })\ngetBrowserData(): Observable<Data[]> {\n // Uses browser-only APIs\n}\n// Returns of([]) during SSR\n```\n\n### Use Cases\n\n- Accessing `window` or `document`\n- DOM manipulation\n- Browser storage (localStorage, sessionStorage)\n- Browser-only libraries\n\n### Live Demonstration"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"name": "Throttle",
|
|
225
|
+
"category": "decorators",
|
|
226
|
+
"categoryTitle": "Decorators",
|
|
227
|
+
"dirName": "throttle",
|
|
228
|
+
"routePath": "throttle",
|
|
229
|
+
"importPath": "ngx-oneforall/decorators/throttle",
|
|
230
|
+
"url": "https://love1024.github.io/ngx-oneforall/decorators/throttle",
|
|
231
|
+
"description": "The throttle decorator limits method execution to once per delay period. Unlike debounce, it executes immediately.",
|
|
232
|
+
"fullContent": "The `throttle` decorator limits method execution to once per delay period. Unlike debounce, it executes immediately.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `delay` | `number` | `300` | Delay in milliseconds |\n| `leading` | `boolean` | `true` | Execute on leading edge |\n| `trailing` | `boolean` | `false` | Execute on trailing edge |\n\n### Features\n\n- **Leading edge** - Executes immediately (default)\n- **Trailing edge** - Optional execution after delay\n- **Per-instance** - Separate throttle state per instance\n- **Cached return** - Returns last result during throttle period\n\n### Basic Usage\n\n```typescript\nimport { throttle } from 'ngx-oneforall/decorators/throttle';\n\n@throttle(500)\nhandleScroll() {\n // Executes at most once per 500ms\n}\n```\n\n### With Trailing Edge\n\n```typescript\n@throttle({ delay: 500, trailing: true })\nsavePosition() {\n // Executes on first call AND after 500ms with latest args\n}\n```\n\n### Trailing Only\n\n```typescript\n@throttle({ delay: 1000, leading: false, trailing: true })\nbatchUpdates() {\n // Waits 1000ms, then executes with latest args\n}\n```\n\n### Use Cases\n\n- Scroll event handlers\n- Window resize handlers\n- Rate-limiting API calls\n- Preventing double-clicks\n\n### Live Demonstration"
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"name": "Auto Focus",
|
|
236
|
+
"category": "directives",
|
|
237
|
+
"categoryTitle": "Directives",
|
|
238
|
+
"dirName": "auto-focus",
|
|
239
|
+
"routePath": "auto-focus",
|
|
240
|
+
"importPath": "ngx-oneforall/directives/auto-focus",
|
|
241
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/auto-focus",
|
|
242
|
+
"description": "Automatically focuses an element when rendered, with reactive two-way binding support.",
|
|
243
|
+
"fullContent": "Automatically focuses an element when rendered, with reactive two-way binding support.\n\n## Features\n\n- **Auto Focus** — Focuses the element immediately on render\n- **Two-Way Binding** — Sync focus state with parent via `[(isFocused)]`\n- **SSR Safe** — Only runs in the browser via `afterNextRender`\n\n---\n\n## Installation\n\n```typescript\nimport { AutoFocusDirective } from 'ngx-oneforall/directives/auto-focus';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Auto focus on render -->\n<input autoFocus />\n\n<!-- With two-way binding -->\n<input autoFocus [(isFocused)]=\"focusState\" />\n\n<!-- Read-only binding -->\n<input autoFocus [isFocused]=\"shouldFocus\" />\n```\n\n---\n\n## API Reference\n\n| Input/Output | Type | Default | Description |\n|--------------|------|---------|-------------|\n| `isFocused` | `ModelSignal<boolean>` | `true` | Two-way bindable focus state |\n\n### Host Events\n\n| Event | Behavior |\n|-------|----------|\n| `focus` | Sets `isFocused` to `true` |\n| `blur` | Sets `isFocused` to `false` |\n\n---\n\n## Programmatic Control\n\nUse two-way binding to control focus from your component:\n\n```typescript\n@Component({\n template: `\n <input autoFocus [(isFocused)]=\"isFocused\" />\n <button (click)=\"focusInput()\">Focus Input</button>\n `,\n imports: [AutoFocusDirective]\n})\nexport class MyComponent {\n isFocused = signal(false);\n\n focusInput() {\n this.isFocused.set(true);\n }\n}\n```\n\n---\n\n## Live Demo"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"name": "Click Outside",
|
|
247
|
+
"category": "directives",
|
|
248
|
+
"categoryTitle": "Directives",
|
|
249
|
+
"dirName": "click-outside",
|
|
250
|
+
"routePath": "click-outside",
|
|
251
|
+
"importPath": "ngx-oneforall/directives/click-outside",
|
|
252
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/click-outside",
|
|
253
|
+
"description": "Detects clicks outside an element, useful for closing dropdowns, modals, and popovers.",
|
|
254
|
+
"fullContent": "Detects clicks outside an element, useful for closing dropdowns, modals, and popovers.\n\n## Features\n\n- **Capture Phase** — Detects clicks even when `stopPropagation()` is called\n- **Zone Optimized** — Runs outside Angular zone for better performance\n- **Toggleable** — Enable/disable via `clickOutsideEnabled` input\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { ClickOutsideDirective } from 'ngx-oneforall/directives/click-outside';\n```\n\n---\n\n## Basic Usage\n\n```html\n<div (clickOutside)=\"onClickedOutside($event)\">\n <!-- Dropdown content -->\n</div>\n```\n\n```typescript\nonClickedOutside(event: Event) {\n this.isOpen = false;\n}\n```\n\n---\n\n## API Reference\n\n| Input/Output | Type | Default | Description |\n|--------------|------|---------|-------------|\n| `clickOutside` | `OutputEmitterRef<Event>` | — | Emits when a click occurs outside the element |\n| `clickOutsideEnabled` | `boolean` | `true` | Enables/disables click detection |\n\n---\n\n## Disabling Detection\n\nTemporarily disable outside click detection:\n\n```html\n<div \n (clickOutside)=\"close()\" \n [clickOutsideEnabled]=\"isDropdownOpen\">\n <!-- Only detects outside clicks when dropdown is open -->\n</div>\n```\n\n---\n\n## Common Use Cases\n\n### Dropdown Menu\n\n```typescript\n@Component({\n template: `\n <div class=\"dropdown\" (clickOutside)=\"close()\" [clickOutsideEnabled]=\"isOpen\">\n <button (click)=\"toggle()\">Menu</button>\n @if (isOpen) {\n <ul class=\"menu\">...</ul>\n }\n </div>\n `,\n imports: [ClickOutsideDirective]\n})\nexport class DropdownComponent {\n isOpen = false;\n toggle() { this.isOpen = !this.isOpen; }\n close() { this.isOpen = false; }\n}\n```\n\n---\n\n## Live Demo"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"name": "Click Throttle",
|
|
258
|
+
"category": "directives",
|
|
259
|
+
"categoryTitle": "Directives",
|
|
260
|
+
"dirName": "click-throttle",
|
|
261
|
+
"routePath": "click-throttle",
|
|
262
|
+
"importPath": "ngx-oneforall/directives/click-throttle",
|
|
263
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/click-throttle",
|
|
264
|
+
"description": "Throttles click events to prevent accidental double-clicks and rapid repeated interactions.",
|
|
265
|
+
"fullContent": "Throttles click events to prevent accidental double-clicks and rapid repeated interactions.\n\n## Features\n\n- **Immediate Response** — First click fires instantly (leading edge)\n- **Configurable Delay** — Set throttle interval via `throttleTime` input\n- **Reactive** — Updates throttle duration when input changes\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { ClickThrottleDirective } from 'ngx-oneforall/directives/click-throttle';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Default 1000ms throttle -->\n<button (clickThrottle)=\"submit()\">Submit</button>\n\n<!-- Custom 500ms throttle -->\n<button [throttleTime]=\"500\" (clickThrottle)=\"submit()\">Submit</button>\n```\n\n---\n\n## API Reference\n\n| Input/Output | Type | Default | Description |\n|--------------|------|---------|-------------|\n| `throttleTime` | `number` | `1000` | Minimum interval (ms) between emissions |\n| `clickThrottle` | `OutputEmitterRef<Event>` | — | Emits throttled click events |\n\n---\n\n## How It Works\n\n```\nUser clicks: ●──●●●●──────────●●●──────●\n 0 200 1500 2800 (ms)\n\nWith 1000ms throttle:\nEmits: ●─────────────────●────────●\n 0 1500 2800\n```\n\n- First click in each window is emitted immediately\n- Subsequent clicks within the throttle period are ignored\n\n---\n\n## Common Use Cases\n\n### Prevent Double Submit\n\n```html\n<button [throttleTime]=\"2000\" (clickThrottle)=\"submitForm()\">\n Submit Order\n</button>\n```\n\n### API Request Protection\n\n```typescript\n@Component({\n template: `<button (clickThrottle)=\"loadMore()\">Load More</button>`,\n imports: [ClickThrottleDirective]\n})\nexport class ListComponent {\n loadMore() {\n this.api.fetchNextPage(); // Won't fire more than once per second\n }\n}\n```\n\n---\n\n## Live Demo"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"name": "Date Time",
|
|
269
|
+
"category": "directives",
|
|
270
|
+
"categoryTitle": "Directives",
|
|
271
|
+
"dirName": "datetime",
|
|
272
|
+
"routePath": "datetime",
|
|
273
|
+
"importPath": "ngx-oneforall/directives/datetime",
|
|
274
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/datetime",
|
|
275
|
+
"description": "Apply date/time format masks to input fields, ensuring valid date and time values.",
|
|
276
|
+
"fullContent": "Apply date/time format masks to input fields, ensuring valid date and time values.\n\n## Features\n\n- **Format patterns** — Use familiar patterns like `MM-DD-YYYY`, `HH:mm:ss`\n- **Smart validation** — Validates as you type (e.g., rejects 13 for month)\n- **Date validation** — Validates complete dates (e.g., rejects Feb 30)\n- **Auto-insert separators** — Automatically adds separators like `-`, `/`, `:`\n- **Form validation** — Implements Angular's `Validator` interface\n- **Min/Max dates** — Optional date range constraints\n\n---\n\n## Installation\n\n```typescript\nimport { DateTimeDirective } from 'ngx-oneforall/directives/datetime';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Date input -->\n<input [dateTime]=\"'MM-DD-YYYY HH:mm'\" />\n```\n\n---\n\n## Format Patterns\n\n| Pattern | Description | Valid Range |\n|---------|-------------|-------------|\n| `YYYY` | 4-digit year | 0001-9999 |\n| `YY` | 2-digit year | 00-99 |\n| `MM` | 2-digit month | 01-12 |\n| `M` | 1-2 digit month | 1-12 |\n| `DD` | 2-digit day | 01-31 |\n| `D` | 1-2 digit day | 1-31 |\n| `HH` | 24-hour format | 00-23 |\n| `hh` | 12-hour format | 01-12 |\n| `mm` | Minutes | 00-59 |\n| `ss` | Seconds | 00-59 |\n| `A` | AM/PM (uppercase) | AM, PM |\n| `a` | am/pm (lowercase) | am, pm |\n\n---\n\n## API Reference\n\n| Input | Type | Description |\n|-------|------|-------------|\n| `dateTime` | `string` | The format pattern (required) |\n| `min` | `Date` | Minimum allowed date |\n| `max` | `Date` | Maximum allowed date |\n| `clearIfNotMatch` | `boolean` | Clear on blur if incomplete (default: `false`) |\n| `removeSpecialCharacters` | `boolean` | Remove separators from form value (default: `true`) |\n| `dateTimeChanged` | `output<DateTimeParts>` | Emits parsed date/time parts (day, month, year, etc.) |\n\n---\n\n## Validation\n\nThe directive validates:\n1. **Format compliance** — Input matches the specified pattern\n2. **Date validity** — The date actually exists (e.g., Feb 30 is rejected)\n3. **Range constraints** — Date is within min/max if specified\n\n```typescript\n// Error object structure\n{\n dateTime: {\n requiredFormat: 'MM-DD-YYYY',\n actualLength: 5,\n expectedLength: 10\n }\n}\n\n// For invalid dates\n{\n dateTime: {\n message: 'Invalid date: 2/30/2024 does not exist',\n invalidDate: true\n }\n}\n```\n\n```html\n<input [dateTime]=\"'MM-DD-YYYY'\" [formControl]=\"dateControl\" />\n@if (dateControl.errors?.['dateTime']; as error) {\n <span class=\"error\"> error.message || 'Incomplete: ' + error.actualLength + '/' + error.expectedLength {{ '}' }}{{ '}' }}</span>\n}\n```\n\n---\n\n## Reactive Forms Example\n\n```typescript\n@Component({\n template: '<input [dateTime]=\"format\" [formControl]=\"dateControl\" />'\n})\nexport class MyComponent {\n format = 'MM-DD-YYYY';\n dateControl = new FormControl('');\n}\n```\n\n---\n\n## Output Event\n\nThe `dateTimeChanged` output emits a object with decomposed date parts.\n\n```html\n<input [dateTime]=\"'MM-DD-YYYY hh:mm:ss A'\" (dateTimeChanged)=\"onDateTimeChanged($event)\" />\n```\n\n```typescript\nonDateTimeChanged(parts: DateTimeParts) {\n console.log(parts);\n // { day: \"01\", month: \"12\", year: \"2024\", hour: \"12\", minute: \"30\", second: \"45\", dayPeriod: \"PM\" }\n}\n```\n\n---\n\n## Demo"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"name": "Drag Auto Scroll",
|
|
280
|
+
"category": "directives",
|
|
281
|
+
"categoryTitle": "Directives",
|
|
282
|
+
"dirName": "drag-auto-scroll",
|
|
283
|
+
"routePath": "drag-auto-scroll",
|
|
284
|
+
"importPath": "ngx-oneforall/directives/drag-auto-scroll",
|
|
285
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/drag-auto-scroll",
|
|
286
|
+
"description": "Automatically scrolls a container when a dragged item approaches the top or bottom edge. Apply to any scrollable element used with drag-and-drop.",
|
|
287
|
+
"fullContent": "Automatically scrolls a container when a dragged item approaches the top or bottom edge. Apply to any scrollable element used with drag-and-drop.\n\n## Features\n\n- **CDK & Native Compatible** — Listens on `document` so it works with CDK drag-drop and native HTML5 drag\n- **Proportional Speed** — Scrolls faster as the cursor gets closer to the edge\n- **Horizontal Bounds** — Only triggers when the cursor is horizontally over the container (with configurable tolerance)\n- **Configurable** — Customize margin zone, max speed, and horizontal tolerance\n- **Zone Optimized** — Runs outside Angular zone for better performance\n- **SSR Safe** — Only activates in the browser\n- **Toggleable** — Enable/disable via `dragAutoScrollDisabled` input\n\n---\n\n## Installation\n\n```typescript\nimport { DragAutoScrollDirective } from 'ngx-oneforall/directives/drag-auto-scroll';\n```\n\n---\n\n## Basic Usage\n\n```html\n<ul dragAutoScroll style=\"overflow-y: auto; height: 400px\">\n @for (item of items; track $index) {\n <li draggable=\"true\"></li>\n }\n</ul>\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|---|---|---|---|\n| `dragAutoScrollMargin` | `number` | `50` | Edge zone height (px) that triggers scrolling |\n| `dragAutoScrollSpeed` | `number` | `10` | Maximum scroll speed (px/frame) |\n| `dragAutoScrollTolerance` | `number` | `50` | Horizontal tolerance (px) outside container bounds above which scrolling does not trigger |\n| `dragAutoScrollDisabled` | `boolean` | `false` | Disables auto-scroll behavior |\n\n### `dragAutoScrollMargin`\n\nDefines the height (in pixels) of the invisible zone at the top and bottom edges of the container. When the cursor enters this zone during a drag, scrolling begins. Larger values make it easier to trigger scrolling, smaller values require the cursor to be closer to the edge.\n\n### `dragAutoScrollSpeed`\n\nThe maximum scroll speed in pixels per animation frame. The actual speed scales proportionally — when the cursor is at the very edge, it scrolls at full speed; at the outer boundary of the margin zone, it scrolls slowly. Increase for long lists where users need to scroll quickly.\n\n### `dragAutoScrollTolerance`\n\nHow far (in pixels) the cursor can be **horizontally** outside the container's left/right edges before scrolling stops. This prevents accidental scrolling when the cursor drifts sideways during a drag. Set to `0` to require the cursor to be strictly inside the container horizontally.\n\n### `dragAutoScrollDisabled`\n\nWhen `true`, the directive stops responding to drag events entirely. Useful for conditionally disabling auto-scroll based on application state.\n\n---\n\n## Custom Configuration\n\nIncrease the edge zone and scroll speed for large lists:\n\n```html\n<div\n dragAutoScroll\n [dragAutoScrollMargin]=\"80\"\n [dragAutoScrollSpeed]=\"15\"\n style=\"overflow-y: auto; max-height: 600px\"\n>\n <!-- draggable content -->\n</div>\n```\n\n---\n\n## How It Works\n\n1. The directive listens for `dragover` events on `document` (works even when a drag preview covers the container)\n2. It checks the cursor is horizontally within the container bounds (± tolerance)\n3. When the cursor enters the top or bottom margin zone, scrolling starts via `requestAnimationFrame`\n4. Scroll speed scales linearly — the closer to the edge, the faster it scrolls\n5. Scrolling stops on `drop`, `dragend`, or when the cursor moves to the center or outside bounds\n\n---\n\n## Live Demo"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "Draggable",
|
|
291
|
+
"category": "directives",
|
|
292
|
+
"categoryTitle": "Directives",
|
|
293
|
+
"dirName": "draggable",
|
|
294
|
+
"routePath": "draggable",
|
|
295
|
+
"importPath": "ngx-oneforall/directives/draggable",
|
|
296
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/draggable",
|
|
297
|
+
"description": "Makes any element draggable with mouse and touch support. Perfect for movable popups, modals, and floating panels.",
|
|
298
|
+
"fullContent": "Makes any element draggable with mouse and touch support. Perfect for movable popups, modals, and floating panels.\n\n## Features\n\n- **Mouse & Touch** — Works seamlessly with both input methods\n- **Drag Handle** — Separate drag handle from the moved element\n- **Boundary Constraints** — Limit dragging to viewport, parent, or custom element\n- **Zone Optimized** — Runs outside Angular zone for better performance\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { DraggableDirective, DraggableDragEvent } from 'ngx-oneforall/directives/draggable';\n```\n\n---\n\n## Basic Usage\n\nMake any element draggable:\n\n```html\n<div makeDraggable style=\"position: absolute;\">\n Drag me around!\n</div>\n```\n\n---\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `makeDraggableEnabled` | `boolean` | `true` | Enables/disables dragging |\n| `makeDraggableTarget` | `HTMLElement \\| null` | `null` | Element to move (defaults to host element) |\n| `makeDraggableBoundary` | `'viewport' \\| 'parent' \\| HTMLElement \\| null` | `null` | Constrains dragging within bounds |\n| `makeDraggableThreshold` | `number` | `5` | Minimum distance (px) before drag starts |\n\n### Outputs\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `dragStart` | `DraggableDragEvent` | Emits when dragging begins |\n| `dragMove` | `DraggableDragEvent` | Emits continuously while dragging |\n| `dragEnd` | `DraggableDragEvent` | Emits when dragging ends |\n\n### DraggableDragEvent Interface\n\n```typescript\ninterface DraggableDragEvent {\n x: number; // Current X position relative to viewport\n y: number; // Current Y position relative to viewport\n deltaX: number; // Change in X since last event\n deltaY: number; // Change in Y since last event\n originalEvent: MouseEvent | TouchEvent;\n}\n```\n\n---\n\n## Modal with Drag Handle\n\nThe most common use case — drag a modal by its header:\n\n```typescript\n@Component({\n template: `\n <div class=\"modal\" #modal>\n <div class=\"modal-header\" makeDraggable [makeDraggableTarget]=\"modal\">\n <span>Settings</span>\n <button (click)=\"close()\">×</button>\n </div>\n <div class=\"modal-body\">\n Modal content here...\n </div>\n </div>\n `,\n imports: [DraggableDirective]\n})\nexport class ModalComponent {}\n```\n\n---\n\n## Boundary Constraints\n\n### Constrain to Viewport\n\n```html\n<div makeDraggable [makeDraggableBoundary]=\"'viewport'\">\n Can't leave the screen!\n</div>\n```\n\n### Constrain to Parent\n\n```html\n<div class=\"container\">\n <div makeDraggable [makeDraggableBoundary]=\"'parent'\">\n Stays within container\n </div>\n</div>\n```\n\n### Constrain to Custom Element\n\n```html\n<div #bounds class=\"bounds\">\n <div makeDraggable [makeDraggableBoundary]=\"bounds\">\n Stays within bounds\n </div>\n</div>\n```\n\n---\n\n## Event Handling\n\nTrack drag position and state:\n\n```typescript\n@Component({\n template: `\n <div makeDraggable\n (dragStart)=\"onDragStart($event)\"\n (dragMove)=\"onDragMove($event)\"\n (dragEnd)=\"onDragEnd($event)\">\n Drag me!\n </div>\n <p>Position: (\"}}, \"}})</p>\n <p>Status: \"}}</p>\n `,\n imports: [DraggableDirective]\n})\nexport class TrackingComponent {\n position = { x: 0, y: 0 };\n isDragging = false;\n\n onDragStart(event: DraggableDragEvent) {\n this.isDragging = true;\n }\n\n onDragMove(event: DraggableDragEvent) {\n this.position = { x: event.x, y: event.y };\n }\n\n onDragEnd(event: DraggableDragEvent) {\n this.isDragging = false;\n }\n}\n```\n\n---\n\n## Multiple Draggable Popups\n\nEach popup maintains its own position independently:\n\n```typescript\n@Component({\n template: `\n @for (popup of popups; track popup.id) {\n <div class=\"popup\"\n style=\"position: absolute;\"\n makeDraggable\n [makeDraggableBoundary]=\"'viewport'\">\n <div class=\"popup-header\">\"}}</div>\n <div class=\"popup-content\">\"}}</div>\n </div>\n }\n `,\n imports: [DraggableDirective]\n})\nexport class MultiPopupComponent {\n popups = [\n { id: 1, title: 'Popup 1', content: 'Content...' },\n { id: 2, title: 'Popup 2', content: 'Content...' },\n ];\n}\n```\n\n---\n\n## Conditionally Enable\n\n```html\n<div makeDraggable\n [makeDraggableEnabled]=\"isEditMode\"\n (dragEnd)=\"savePosition($event)\">\n \"}}\n</div>\n```\n\n---\n\n## Live Demo"
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "Hover Class",
|
|
302
|
+
"category": "directives",
|
|
303
|
+
"categoryTitle": "Directives",
|
|
304
|
+
"dirName": "hover-class",
|
|
305
|
+
"routePath": "hover-class",
|
|
306
|
+
"importPath": "ngx-oneforall/directives/hover-class",
|
|
307
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/hover-class",
|
|
308
|
+
"description": "Dynamically applies CSS classes on hover with reactive updates and toggle support.",
|
|
309
|
+
"fullContent": "Dynamically applies CSS classes on hover with reactive updates and toggle support.\n\n## Features\n\n- **Multiple Classes** — Apply one or more space-separated classes\n- **Toggleable** — Enable/disable via `hoverClassEnabled` input\n- **Auto Cleanup** — Classes removed automatically when disabled\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { HoverClassDirective } from 'ngx-oneforall/directives/hover-class';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Single class -->\n<button hoverClass=\"highlight\">Hover me</button>\n\n<!-- Multiple classes -->\n<div hoverClass=\"shadow-lg border-primary\">Hover card</div>\n\n<!-- Conditional enable -->\n<span hoverClass=\"underline\" [hoverClassEnabled]=\"isActive()\">Link</span>\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `hoverClass` | `string` | *required* | Space-separated CSS classes to apply on hover |\n| `hoverClassEnabled` | `boolean` | `true` | Enables/disables the hover effect |\n\n---\n\n## Behavior\n\n| State | Action |\n|-------|--------|\n| Mouse enter (enabled) | Adds all specified classes |\n| Mouse leave (enabled) | Removes all specified classes |\n| `hoverClassEnabled=false` | Immediately removes any applied classes |\n| `hoverClass` changes | Updates classes to toggle on next hover |\n\n---\n\n## Common Use Cases\n\n### Button Hover Effect\n\n```html\n<button hoverClass=\"bg-primary text-white scale-105\">\n Submit\n</button>\n```\n\n### Card Hover Shadow\n\n```typescript\n@Component({\n template: `\n <div class=\"card\" hoverClass=\"shadow-xl transform-up\">\n \n </div>\n `,\n imports: [HoverClassDirective]\n})\nexport class CardComponent {}\n```\n\n---\n\n## Live Demo"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"name": "Infinite Scroll",
|
|
313
|
+
"category": "directives",
|
|
314
|
+
"categoryTitle": "Directives",
|
|
315
|
+
"dirName": "infinite-scroll",
|
|
316
|
+
"routePath": "infinite-scroll",
|
|
317
|
+
"importPath": "ngx-oneforall/directives/infinite-scroll",
|
|
318
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/infinite-scroll",
|
|
319
|
+
"description": "Implements infinite scroll behavior using IntersectionObserver for efficient detection.",
|
|
320
|
+
"fullContent": "Implements infinite scroll behavior using IntersectionObserver for efficient detection.\n\n## Features\n\n- **IntersectionObserver** — No scroll event listeners, better performance\n- **Reactive** — Automatically reinitializes when inputs change\n- **Flexible Container** — Works with window, custom container, or auto-detects parent\n- **Configurable Threshold** — Control trigger distance via `bottomMargin`\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { InfiniteScrollDirective } from 'ngx-oneforall/directives/infinite-scroll';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Window scrolling (default) -->\n<div infiniteScroll (scrolled)=\"loadMore()\">\n @for (item of items(); track item.id) {\n <div></div>\n }\n</div>\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `bottomMargin` | `number` | `20` | Distance (%) from bottom to trigger |\n| `useWindow` | `boolean` | `true` | Use window vs container scroll |\n| `scrollContainer` | `string` | `null` | CSS selector for custom container |\n| `disabled` | `boolean` | `false` | Disable scroll detection |\n| `checkOnInit` | `boolean` | `true` | Emit on initial render if visible |\n| `initDelay` | `number` | `1000` | Delay (ms) to ignore initial intersections |\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `scrolled` | `void` | Emits when scroll reaches threshold |\n\n---\n\n## Container Scrolling\n\nFor a specific scrollable container:\n\n```html\n<div \n class=\"scroll-container\" \n infiniteScroll \n [useWindow]=\"false\"\n [scrollContainer]=\"'.scroll-container'\"\n (scrolled)=\"loadMore()\">\n <!-- Items -->\n</div>\n```\n\n---\n\n## Common Use Cases\n\n### Paginated List\n\n```typescript\n@Component({\n template: `\n <div infiniteScroll (scrolled)=\"loadNextPage()\" [disabled]=\"loading()\">\n @for (item of items(); track item.id) {\n <app-item [data]=\"item\" />\n }\n @if (loading()) {\n <div class=\"spinner\">Loading...</div>\n }\n </div>\n `,\n imports: [InfiniteScrollDirective]\n})\nexport class ListComponent {\n items = signal<Item[]>([]);\n loading = signal(false);\n page = 0;\n\n loadNextPage() {\n this.loading.set(true);\n this.api.getItems(++this.page).subscribe(newItems => {\n this.items.update(items => [...items, ...newItems]);\n this.loading.set(false);\n });\n }\n}\n```\n\n---\n\n## Live Demo"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"name": "Lowercase",
|
|
324
|
+
"category": "directives",
|
|
325
|
+
"categoryTitle": "Directives",
|
|
326
|
+
"dirName": "lowercase",
|
|
327
|
+
"routePath": "lowercase",
|
|
328
|
+
"importPath": "ngx-oneforall/directives/lowercase",
|
|
329
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/lowercase",
|
|
330
|
+
"description": "The lowercase directive automatically transforms the input value to lowercase as the user types.",
|
|
331
|
+
"fullContent": "The `lowercase` directive automatically transforms the input value to lowercase as the user types.\n\n### Import\n\n```typescript\nimport { LowercaseDirective } from 'ngx-oneforall/directives/lowercase';\n```\n\n### Usage\n\nAdd the `lowercase` attribute to any `input` or `textarea` element.\n\n```html\n<input type=\"text\" lowercase />\n```\n\n### Features\n\n- **Auto-transform**: Converts text to lowercase on input and blur events.\n- **Model Update**: Updates the underlying `FormControl` or `ngModel` value if attached.\n- **Paste Support**: Handles pasted content correctly.\n- **Visual-Only Mode**: Use `[updateOutput]=\"false\"` to transform visually via CSS but keep the original model value.\n\n### Configuration\n\n| Input | Type | Default | Description |\n| :--- | :--- | :--- | :--- |\n| `updateOutput` | `boolean` | `true` | If `true` (default), transforms the value and updates the model. If `false`, applies CSS `text-transform: lowercase` only. |\n\n### Live Demonstration"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"name": "Mask",
|
|
335
|
+
"category": "directives",
|
|
336
|
+
"categoryTitle": "Directives",
|
|
337
|
+
"dirName": "mask",
|
|
338
|
+
"routePath": "mask",
|
|
339
|
+
"importPath": "ngx-oneforall/directives/mask",
|
|
340
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/mask",
|
|
341
|
+
"description": "Apply input masks to format user input as they type.",
|
|
342
|
+
"fullContent": "Apply input masks to format user input as they type.\n\n## Features\n\n- **Pattern-based masking** — Define mask patterns using simple characters\n- **Quantifiers** — Use `?` (optional) and `*` (zero or more) for flexible patterns\n- **Auto-insert separators** — Automatically adds separators like `-`, `/`, `(`, `)`\n- **Prefix & Suffix** — Add unmodifiable prefix and suffix strings\n- **Form validation** — Implements Angular's `Validator` interface for reactive forms\n- **SSR Safe** — Only runs in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { MaskDirective } from 'ngx-oneforall/directives/mask';\n```\n\n---\n\n## Basic Usage\n\n```html\n<!-- Phone number -->\n<input [mask]=\"'(###) ###-####'\" />\n\n<!-- Credit card -->\n<input [mask]=\"'#### #### #### ####'\" />\n```\n\n---\n\n## Pattern Characters\n\n| Pattern | Description | Example |\n|---------|-------------|---------|\n| `#` | Required digit (0-9) | `###` → \"123\" |\n| `A` | Required alphanumeric | `AAA` → \"A1B\" |\n| `@` | Required letter (a-z, A-Z) | `@@@` → \"ABC\" |\n| `U` | Required uppercase letter | `UUU` → \"ABC\" |\n| `L` | Required lowercase letter | `LLL` → \"abc\" |\n\n---\n\n## Quantifiers\n\n| Quantifier | Description |\n|------------|-------------|\n| `?` | Makes the preceding pattern optional (0 or 1 match) |\n| `*` | Matches zero or more of the preceding pattern |\n\n### Practical Examples\n\n**Optional (`?`):**\n```html\n<!-- IP address (1-3 digits per octet) -->\n<input [mask]=\"'#?#?#.#?#?#.#?#?#.#?#?#'\" />\n\n<!-- License plate: \"ABC-1234\" or \"AB-1234\" -->\n<input [mask]=\"'@@?@?-####'\" />\n```\n\n**Zero or more (`*`):**\n```html\n<!-- Email: \"user@domain.com\" -->\n<input [mask]=\"'A*\\@A*.A*'\" />\n\n<!-- Hashtag: \"#a\", \"#hello\", \"#Angular\" -->\n<input [mask]=\"'\\#@*'\" />\n```\n\n---\n\n## API Reference\n\n| Input | Type | Description |\n|-------|------|-------------|\n| `mask` | `string` | The mask pattern to apply |\n| `prefix` | `string` | Text to prepend to the masked value |\n| `suffix` | `string` | Text to append to the masked value |\n| `customPatterns` | `Record<string, IConfigPattern>` | Custom patterns to extend or override built-in patterns |\n| `clearIfNotMatch` | `boolean` | If `true`, clears the input on blur when mask is incomplete (default: `false`) |\n| `specialCharacters` | `string[]` | List of characters to be treated as separators/literals. These are the ONLY non-pattern characters allowed in the mask. By default, they are removed from the raw value. (default: `['-', '/', '(', ')', '.', ':', ' ', '+', ',', '@', '[', ']', '\"', \"'\"]`) |\n| `mergeSpecialChars` | `boolean` | If `true`, merges your `specialCharacters` list with the default list. If `false` (default), uses ONLY your provided list. |\n| `removeSpecialCharacters` | `boolean` | If `true`, removes characters defined in `specialCharacters` from the raw value. If `false`, includes them. (default: `true`) |\n\n### Special Characters Configuration\n\nBy default, the directive defines common separators (like `-`, `/`, `(`) as special characters. These characters play two roles:\n1. They are **allowed** in your mask pattern as literals.\n2. They are **removed** from the model value (raw value) by default (unless `removeSpecialCharacters` is `false`).\n\n> **Warning** If your mask contains any literal characters (characters that are not patterns like `0` or `A`) that are NOT in the `specialCharacters` list (either the default list or your custom one), the directive will throw an error.\n\n**Example: Custom Special Characters**\n\n```html\n<input [mask]=\"'A-A'\" [specialCharacters]=\"['-']\" /> \n<!-- Valid because '-' is in specialCharacters -->\n\n<input [mask]=\"'A*A'\" [specialCharacters]=\"['-']\" /> \n<!-- ERROR: '*' is not a pattern and not in specialCharacters -->\n```\n\n**Example: Keep Special Characters in Raw Value**\n\n```html\n<input \n [mask]=\"'AAA-###/###'\" \n [specialCharacters]=\"['-', '/']\"\n [removeSpecialCharacters]=\"false\" /> \n<!-- Input: \"ABC-123/456\" -> Raw Value: \"ABC-123/456\" -->\n<!-- '-' and '/' are kept because they are in specialCharacters and removeSpecialCharacters is false. -->\n```\n\n### IConfigPattern Interface\n\n```typescript\ninterface IConfigPattern {\n pattern: RegExp; // The regex pattern to match\n optional?: boolean; // If true, equivalent to ? quantifier\n}\n```\n\n---\n\n## Custom Patterns\n\nDefine your own pattern characters or override built-in ones:\n\n```html\n<!-- Custom hex digit pattern -->\n<input \n [mask]=\"'XX-XX-XX'\" \n [customPatterns]=\"{ X: { pattern: /[0-9A-Fa-f]/ } }\" />\n\n\n\n<!-- Optional pattern via property -->\n<input \n [mask]=\"'O##'\" \n [customPatterns]=\"{ O: { pattern: /\\\\d/, optional: true } }\" />\n```\n\n---\n\n## Validation\n\nThe directive implements Angular's `Validator` interface. When used with reactive forms, it returns a `mask` error if the input is incomplete:\n\n```typescript\n// Error object when input is incomplete\n{\n mask: {\n requiredMask: '(###) ###-####', // The mask pattern\n actualLength: 4, // Current length of the value\n expectedLength: 10 // Expected length based on mask\n }\n}\n```\n\n```html\n<input [formControl]=\"phone\" [mask]=\"'(###) ###-####'\" />\n@if (phone.errors?.['mask']) {\n <span class=\"error\">\n Incomplete: phone.errors['mask'].actualLength }}/ phone.errors['mask'].expectedLength }} characters\n </span>\n}\n```\n\n---\n\n## Demo"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"name": "Numbers Only",
|
|
346
|
+
"category": "directives",
|
|
347
|
+
"categoryTitle": "Directives",
|
|
348
|
+
"dirName": "numbers-only",
|
|
349
|
+
"routePath": "numbers-only",
|
|
350
|
+
"importPath": "ngx-oneforall/directives/numbers-only",
|
|
351
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/numbers-only",
|
|
352
|
+
"description": "Restricts user input to valid numeric values with configurable decimal places and negative number support.",
|
|
353
|
+
"fullContent": "Restricts user input to valid numeric values with configurable decimal places and negative number support.\n\n## Features\n\n- **Input Validation** — Blocks non-numeric characters on input, paste, and cut\n- **Decimal Control** — Configure allowed decimal places\n- **Negative Support** — Optionally allow negative numbers\n- **Custom Separator** — Use any decimal separator (`.`, `,`, etc.)\n- **Forms Compatible** — Works with both native inputs and Angular forms\n\n---\n\n## Installation\n\n```typescript\nimport { NumbersOnlyDirective } from 'ngx-oneforall/directives/numbers-only';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `decimals` | `number` | `0` | Decimal places allowed (0 = integers only) |\n| `negative` | `boolean` | `false` | Allow negative numbers |\n| `separator` | `string` | `'.'` | Decimal separator character |\n\n---\n\n## Basic Usage\n\n```html\n<!-- Integers only (default) -->\n<input numbersOnly />\n\n<!-- Allow 2 decimal places -->\n<input numbersOnly [decimals]=\"2\" />\n\n<!-- Allow negative values -->\n<input numbersOnly [negative]=\"true\" />\n\n<!-- Custom separator (comma) -->\n<input numbersOnly [decimals]=\"2\" [separator]=\"','\" />\n```\n\n---\n\n## Common Use Cases\n\n### Currency Input\n\n```html\n<input \n numbersOnly \n [decimals]=\"2\" \n placeholder=\"$0.00\" />\n```\n\n### Quantity Field\n\n```html\n<input \n numbersOnly \n [negative]=\"true\" \n placeholder=\"Enter quantity\" />\n```\n\n### Reactive Forms\n\n```typescript\n@Component({\n template: `<input numbersOnly [decimals]=\"2\" [formControl]=\"price\" />`,\n imports: [NumbersOnlyDirective, ReactiveFormsModule]\n})\nexport class PriceFormComponent {\n price = new FormControl('');\n}\n```\n\n---\n\n## Live Demo"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"name": "Press Enter",
|
|
357
|
+
"category": "directives",
|
|
358
|
+
"categoryTitle": "Directives",
|
|
359
|
+
"dirName": "press-enter",
|
|
360
|
+
"routePath": "press-enter",
|
|
361
|
+
"importPath": "ngx-oneforall/directives/press-enter",
|
|
362
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/press-enter",
|
|
363
|
+
"description": "Emits an event when the Enter key is pressed on any element.",
|
|
364
|
+
"fullContent": "Emits an event when the Enter key is pressed on any element.\n\n## Features\n\n- **Enter Key Detection** — Listens for `keydown.enter` event\n- **Prevent Default** — Optionally prevents form submission\n- **Simple API** — Just add the directive and listen\n\n---\n\n## Installation\n\n```typescript\nimport { PressEnterDirective } from 'ngx-oneforall/directives/press-enter';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `preventDefault` | `boolean` | `true` | Prevent default Enter behavior |\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `pressEnter` | `void` | Emits when Enter is pressed |\n\n---\n\n## Basic Usage\n\n```html\n<input (pressEnter)=\"onSubmit()\" placeholder=\"Press Enter\" />\n```\n\n```typescript\nonSubmit() {\n console.log('Enter pressed!');\n}\n```\n\n---\n\n## Common Use Cases\n\n### Search Input\n\n```html\n<input \n [(ngModel)]=\"searchQuery\"\n (pressEnter)=\"search()\"\n placeholder=\"Search...\" />\n```\n\n### Chat Message\n\n```html\n<input \n [(ngModel)]=\"message\"\n (pressEnter)=\"sendMessage()\"\n placeholder=\"Type a message...\" />\n```\n\n### Allow Default Behavior\n\n```html\n<!-- Don't prevent form submission -->\n<input \n (pressEnter)=\"onEnter()\" \n [preventDefault]=\"false\" />\n```\n\n---\n\n## Live Demo"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"name": "Repeat",
|
|
368
|
+
"category": "directives",
|
|
369
|
+
"categoryTitle": "Directives",
|
|
370
|
+
"dirName": "repeat",
|
|
371
|
+
"routePath": "repeat",
|
|
372
|
+
"importPath": "ngx-oneforall/directives/repeat",
|
|
373
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/repeat",
|
|
374
|
+
"description": "A structural directive that repeats a template a specified number of times.",
|
|
375
|
+
"fullContent": "A structural directive that repeats a template a specified number of times.\n\n## Features\n\n- **Reactive** — Re-renders when count changes\n- **Rich Context** — Exposes index, first, last, even, odd\n- **Safe** — Handles negative numbers gracefully\n\n---\n\n## Installation\n\n```typescript\nimport { RepeatDirective } from 'ngx-oneforall/directives/repeat';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `repeat` | `number` | `1` | Number of times to repeat |\n\n### Context Variables\n\n| Variable | Type | Description |\n|----------|------|-------------|\n| `$implicit` | `number` | Current index (0-based) |\n| `index` | `number` | Same as `$implicit` |\n| `first` | `boolean` | True if first iteration |\n| `last` | `boolean` | True if last iteration |\n| `even` | `boolean` | True if index is even |\n| `odd` | `boolean` | True if index is odd |\n\n---\n\n## Basic Usage\n\n```html\n<div *repeat=\"5; let i\">\n Item \n</div>\n```\n\n---\n\n## Using Context Variables\n\n```html\n<ng-container *repeat=\"3; let i; let isFirst = first; let isLast = last; let isEven = even\">\n <span>Index: </span>\n @if (isFirst) { <span>← First</span> }\n @if (isLast) { <span>← Last</span> }\n @if (isEven) { <span>← Even</span> }\n</ng-container>\n```\n\n---\n\n## Common Use Cases\n\n### Star Rating\n\n```html\n<span *repeat=\"5; let i\">\n ★\n</span>\n```\n\n### Skeleton Loaders\n\n```html\n<div *repeat=\"3\" class=\"skeleton-row\"></div>\n```\n\n### Pagination Dots\n\n```html\n<span *repeat=\"pageCount; let i\" \n [class.active]=\"i === currentPage\"\n (click)=\"goToPage(i)\">\n ●\n</span>\n```\n\n---\n\n## Live Demo"
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"name": "Resized",
|
|
379
|
+
"category": "directives",
|
|
380
|
+
"categoryTitle": "Directives",
|
|
381
|
+
"dirName": "resized",
|
|
382
|
+
"routePath": "resized",
|
|
383
|
+
"importPath": "ngx-oneforall/directives/resized",
|
|
384
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/resized",
|
|
385
|
+
"description": "Detects element resize events using ResizeObserver and emits current/previous dimensions.",
|
|
386
|
+
"fullContent": "Detects element resize events using ResizeObserver and emits current/previous dimensions.\n\n## Features\n\n- **ResizeObserver API** — Efficient native resize detection\n- **Previous Dimensions** — Tracks both current and previous size\n- **Debounce Support** — Optional debouncing for rapid resize events\n- **Zone Optimized** — Runs outside Angular zone for performance\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { ResizedDirective, ResizedEvent } from 'ngx-oneforall/directives/resized';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `debounceTime` | `number` | `0` | Debounce time in ms (0 = no debounce) |\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `resized` | `ResizedEvent` | Emits on size change |\n\n### ResizedEvent\n\n```typescript\ninterface ResizedEvent {\n current: DOMRectReadOnly; // Current dimensions\n previous: DOMRectReadOnly | null; // Previous dimensions\n}\n```\n\n---\n\n## Basic Usage\n\n```html\n<div (resized)=\"onResize($event)\">\n Resizable content\n</div>\n```\n\n```typescript\nonResize(event: ResizedEvent) {\n console.log('Width:', event.current.width);\n console.log('Height:', event.current.height);\n}\n```\n\n---\n\n## With Debouncing\n\n```html\n<div (resized)=\"onResize($event)\" [debounceTime]=\"100\">\n Resizable content\n</div>\n```\n\n---\n\n## Common Use Cases\n\n### Responsive Component\n\n```typescript\n@Component({\n template: `\n <div (resized)=\"onResize($event)\">\n @if (isCompact()) {\n <span>Compact</span>\n } @else {\n <span>Full</span>\n }\n </div>\n `,\n imports: [ResizedDirective]\n})\nexport class ResponsiveComponent {\n isCompact = signal(false);\n\n onResize(event: ResizedEvent) {\n this.isCompact.set(event.current.width < 400);\n }\n}\n```\n\n### Size Display\n\n```html\n<div (resized)=\"size.set($event.current)\" style=\"resize: both; overflow: auto;\">\n Width: \"}} x Height: \"}}\n</div>\n```\n\n---\n\n## Live Demo"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"name": "Shortcut",
|
|
390
|
+
"category": "directives",
|
|
391
|
+
"categoryTitle": "Directives",
|
|
392
|
+
"dirName": "shortcut",
|
|
393
|
+
"routePath": "shortcut",
|
|
394
|
+
"importPath": "ngx-oneforall/directives/shortcut",
|
|
395
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/shortcut",
|
|
396
|
+
"description": "Binds keyboard shortcuts to trigger actions with support for modifiers and global/scoped listening.",
|
|
397
|
+
"fullContent": "Binds keyboard shortcuts to trigger actions with support for modifiers and global/scoped listening.\n\n## Features\n\n- **Multiple Shortcuts** — Comma-separated patterns (e.g., `'ctrl.s, meta.s'`)\n- **Modifier Support** — `ctrl`, `shift`, `alt`, `meta` (cmd)\n- **Global/Scoped** — Listen on window or element-only\n- **Layout Independent** — Uses physical key codes for cross-keyboard support\n- **Performance Optimized** — Cached shortcut parsing with computed signals\n\n---\n\n## Installation\n\n```typescript\nimport { ShortcutDirective } from 'ngx-oneforall/directives/shortcut';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `shortcut` | `string` | **Required** | Shortcut pattern(s) |\n| `isGlobal` | `boolean` | `false` | Listen globally on window |\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `action` | `void` | Emits when shortcut is triggered |\n\n### Shortcut Format\n\n```\nmodifier.modifier.key\n```\n\n**Modifiers:** `ctrl`, `shift`, `alt`, `meta`, `cmd`\n\n**Examples:**\n- `ctrl.s` — Ctrl+S\n- `meta.s` — Cmd+S (Mac)\n- `ctrl.shift.s` — Ctrl+Shift+S\n- `ctrl.s, meta.s` — Ctrl+S or Cmd+S\n\n---\n\n## Basic Usage\n\n```html\n<!-- Element scoped (requires focus) -->\n<input [shortcut]=\"'ctrl.s'\" (action)=\"save()\" />\n\n<!-- Global (works anywhere) -->\n<div [shortcut]=\"'ctrl.k'\" [isGlobal]=\"true\" (action)=\"openSearch()\"></div>\n```\n\n---\n\n## Common Use Cases\n\n### Save Shortcut (Cross-Platform)\n\n```html\n<div [shortcut]=\"'ctrl.s, meta.s'\" [isGlobal]=\"true\" (action)=\"save()\">\n Press Ctrl+S or Cmd+S to save\n</div>\n```\n\n### Command Palette\n\n```typescript\n@Component({\n template: `\n <div [shortcut]=\"'ctrl.k, meta.k'\" [isGlobal]=\"true\" (action)=\"openPalette()\">\n @if (paletteOpen()) {\n <command-palette />\n }\n </div>\n `,\n imports: [ShortcutDirective]\n})\nexport class AppComponent {\n paletteOpen = signal(false);\n \n openPalette() {\n this.paletteOpen.set(true);\n }\n}\n```\n\n---\n\n## Live Demo"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"name": "Typed Template",
|
|
401
|
+
"category": "directives",
|
|
402
|
+
"categoryTitle": "Directives",
|
|
403
|
+
"dirName": "typed-template",
|
|
404
|
+
"routePath": "typed-template",
|
|
405
|
+
"importPath": "ngx-oneforall/directives/typed-template",
|
|
406
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/typed-template",
|
|
407
|
+
"description": "The TypedTemplateDirective provides a way to strictly type the context of your ng-template definitions. By default, Angular templates are weakly typed (any or Object), which can lead to runtime errors when accessing properties that don't exist. This directive bridges that gap, leveraging TypeScript's power directly within your templates.",
|
|
408
|
+
"fullContent": "The `TypedTemplateDirective` provides a way to strictly type the context of your `ng-template` definitions. By default, Angular templates are weakly typed (`any` or `Object`), which can lead to runtime errors when accessing properties that don't exist. This directive bridges that gap, leveraging TypeScript's power directly within your templates.\n\n> **Note**\n> This directive is purely for compile-time type checking. It does not affect runtime behavior or inject data into the template. The actual data context must still be provided via `[ngTemplateOutletContext]` or similar mechanisms.\n\n---\n\n### Usage\n\n#### 1. Import the Directive\n\nImport `TypedTemplateDirective` into your component or module.\n\n```typescript\nimport { TypedTemplateDirective } from 'ngx-oneforall/directives/typed-template';\n\n@Component({\n imports: [TypedTemplateDirective],\n // ...\n})\nexport class MyComponent {}\n```\n\n#### 2. Apply to Template\n\nTo type a template, start by defining the interface for your context.\n\n```typescript\ninterface UserContext {\n $implicit: string; // The type for let-name\n age: number; // The type for let-age=\"age\"\n}\n```\n\nThen, use a helper property to pass this type to the directive. This property is used purely for type inference.\n\n```typescript\nprotected get userContextType() {\n return {} as UserContext;\n}\n```\n\nFinally, bind `[typedTemplate]` to your type helper on the `ng-template`.\n\n```html\n<ng-template [typedTemplate]=\"userContextType\" let-name let-age=\"age\">\n <!-- 'name' is strictly typed as string -->\n <!-- 'age' is strictly typed as number -->\n <div>Name: </div>\n <div>Age: </div>\n</ng-template>\n```\n\n---\n\n### Why use it?\n\n1. **Catch Errors Early**: Typo in a property name? Accessing a missing nested field? TypeScript will catch these errors at build time, preventing runtime crashes.\n2. **Better IDE Support**: Enjoy full autocomplete and refactoring capabilities for variables inside your templates, just like in your TypeScript files.\n3. **Clear Contracts**: It explicitly documents the data shape expected by the template, making the code easier to understand and maintain for your team.\n\n---\n\n### Live Demo"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "Uppercase",
|
|
412
|
+
"category": "directives",
|
|
413
|
+
"categoryTitle": "Directives",
|
|
414
|
+
"dirName": "uppercase",
|
|
415
|
+
"routePath": "uppercase",
|
|
416
|
+
"importPath": "ngx-oneforall/directives/uppercase",
|
|
417
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/uppercase",
|
|
418
|
+
"description": "The uppercase directive automatically transforms the input value to uppercase as the user types.",
|
|
419
|
+
"fullContent": "The `uppercase` directive automatically transforms the input value to uppercase as the user types.\n\n### Import\n\n```typescript\nimport { UppercaseDirective } from 'ngx-oneforall/directives/uppercase';\n```\n\n### Usage\n\nAdd the `uppercase` attribute to any `input` or `textarea` element.\n\n```html\n<input type=\"text\" uppercase />\n```\n\n### Features\n\n- **Auto-transform**: Converts text to uppercase on input and blur events.\n- **Model Update**: Updates the underlying `FormControl` or `ngModel` value if attached.\n- **Paste Support**: Handles pasted content correctly.\n- **Visual-Only Mode**: Use `[updateOutput]=\"false\"` to transform visually via CSS but keep the original model value.\n\n### Configuration\n\n| Input | Type | Default | Description |\n| :--- | :--- | :--- | :--- |\n| `updateOutput` | `boolean` | `true` | If `true` (default), transforms the value and updates the model. If `false`, applies CSS `text-transform: uppercase` only. |\n\n### Live Demonstration"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"name": "Visibility Change",
|
|
423
|
+
"category": "directives",
|
|
424
|
+
"categoryTitle": "Directives",
|
|
425
|
+
"dirName": "visibility-change",
|
|
426
|
+
"routePath": "visibility-change",
|
|
427
|
+
"importPath": "ngx-oneforall/directives/visibility-change",
|
|
428
|
+
"url": "https://love1024.github.io/ngx-oneforall/directives/visibility-change",
|
|
429
|
+
"description": "Detects when an element enters or leaves the viewport using IntersectionObserver.",
|
|
430
|
+
"fullContent": "Detects when an element enters or leaves the viewport using IntersectionObserver.\n\n## Features\n\n- **Visibility Detection** — Emits when element becomes visible/hidden\n- **Configurable Threshold** — Control visibility percentage to trigger\n- **Custom Root** — Observe within viewport or custom container\n- **Root Margin** — Adjust intersection area with margin\n- **Zone Optimized** — Observer runs outside Angular zone\n- **SSR Safe** — Only activates in the browser\n\n---\n\n## Installation\n\n```typescript\nimport { VisibilityChangeDirective, VisibilityChange } from 'ngx-oneforall/directives/visibility-change';\n```\n\n---\n\n## API Reference\n\n| Input | Type | Default | Description |\n|-------|------|---------|-------------|\n| `threshold` | `number` | `1.0` | Visibility % to trigger (0-1) |\n| `root` | `HTMLElement \\| null` | `null` | Custom scroll container |\n| `rootMargin` | `string` | `'0px'` | Margin around root |\n\n| Output | Type | Description |\n|--------|------|-------------|\n| `visibilityChange` | `VisibilityChange` | Emits on visibility change |\n\n### VisibilityChange Type\n\n```typescript\ntype VisibilityChange = \n | { isVisible: true; target: HTMLElement }\n | { isVisible: false; target: HTMLElement | undefined };\n```\n\n---\n\n## Basic Usage\n\n```html\n<div (visibilityChange)=\"onVisible($event)\">\n Watch me!\n</div>\n```\n\n```typescript\nonVisible(event: VisibilityChange) {\n if (event.isVisible) {\n console.log('Element is visible');\n }\n}\n```\n\n---\n\n## Common Use Cases\n\n### Lazy Load Content\n\n```typescript\n@Component({\n template: `\n <div (visibilityChange)=\"onVisible($event)\" [threshold]=\"0.1\">\n @if (loaded()) {\n <heavy-component />\n } @else {\n <div class=\"placeholder\">Loading...</div>\n }\n </div>\n `,\n imports: [VisibilityChangeDirective]\n})\nexport class LazyComponent {\n loaded = signal(false);\n\n onVisible(event: VisibilityChange) {\n if (event.isVisible && !this.loaded()) {\n this.loaded.set(true);\n }\n }\n}\n```\n\n### Animate on Scroll\n\n```html\n<div \n (visibilityChange)=\"visible.set($event.isVisible)\"\n [threshold]=\"0.5\"\n [class.animate-in]=\"visible()\">\n Animated content\n</div>\n```\n\n---\n\n## Live Demo"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"name": "Param Guard",
|
|
434
|
+
"category": "guards",
|
|
435
|
+
"categoryTitle": "Guards",
|
|
436
|
+
"dirName": "param",
|
|
437
|
+
"routePath": "param",
|
|
438
|
+
"importPath": "ngx-oneforall/guards/param",
|
|
439
|
+
"url": "https://love1024.github.io/ngx-oneforall/guards/param",
|
|
440
|
+
"description": "To use paramGuard, provide it in your route configuration using canActivate. It is particularly useful for validating required parameters in routes like /item/:id.",
|
|
441
|
+
"fullContent": "`paramGuard` is a functional guard that validates route parameters (path variables) before allowing activation of a route. It works similarly to `queryParamGuard` but for route parameters.\n\n## Usage\n\nTo use `paramGuard`, provide it in your route configuration using `canActivate`. It is particularly useful for validating required parameters in routes like `/item/:id`.\n\n```typescript\nimport { paramGuard } from 'ngx-oneforall/guards/param';\n\nconst routes: Routes = [\n {\n path: 'users/:id',\n component: UserComponent,\n canActivate: [\n paramGuard({\n required: ['id'],\n // predicate: (params) => params['id'].startsWith('usr_'),\n redirectTo: '/not-found',\n }),\n ],\n },\n];\n```\n\n## Configuration\n\nThe `paramGuard` factory takes a `ParamGuardConfig` object:\n\n| Property | Type | Description |\n| ------------ | ------------------------------------------ | --------------------------------------------------------------------------- |\n| `required` | `string[]` | List of parameter keys that must be present and non-empty. |\n| `predicate` | `(params: Record<string, string>) => boolean` | A custom function to validate parameters. |\n| `redirectTo` | `string` | Optional URL to redirect to if validation fails (uses `RedirectCommand`). |\n\n## Demo"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"name": "Query Param Guard",
|
|
445
|
+
"category": "guards",
|
|
446
|
+
"categoryTitle": "Guards",
|
|
447
|
+
"dirName": "query-param",
|
|
448
|
+
"routePath": "query-param",
|
|
449
|
+
"importPath": "ngx-oneforall/guards/query-param",
|
|
450
|
+
"url": "https://love1024.github.io/ngx-oneforall/guards/query-param",
|
|
451
|
+
"description": "To use queryParamGuard, provide it in your route configuration using canActivate:",
|
|
452
|
+
"fullContent": "`queryParamGuard` is a functional guard that validates query parameters before allowing activation of a route. It can check for required parameters and apply custom logic via a predicate function.\n\n## Usage\n\nTo use `queryParamGuard`, provide it in your route configuration using `canActivate`:\n\n```typescript\nimport { queryParamGuard } from 'ngx-oneforall/guards/query-param';\n\nconst routes: Routes = [\n {\n path: 'protected',\n component: ProtectedComponent,\n canActivate: [\n queryParamGuard({\n required: ['id'],\n predicate: (params) => params['type'] === 'admin',\n redirectTo: '/unauthorized',\n }),\n ],\n },\n];\n```\n\n## Configuration\n\nThe `queryParamGuard` factory takes a `QueryParamGuardConfig` object:\n\n| Property | Type | Description |\n| ------------ | ------------------------------------------ | --------------------------------------------------------------------------- |\n| `required` | `string[]` | List of query parameter keys that must be present and non-empty. |\n| `predicate` | `(params: Params) => boolean` | A custom function to validate query parameters. |\n| `redirectTo` | `string` | Optional URL to redirect to if validation fails (uses `RedirectCommand`). |\n\n## Demo\n\n\n\n> **Note**\n> If `redirectTo` is not provided, the guard will simply return `false` on failure."
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"name": "Unsaved Changes Guard",
|
|
456
|
+
"category": "guards",
|
|
457
|
+
"categoryTitle": "Guards",
|
|
458
|
+
"dirName": "unsaved-changes",
|
|
459
|
+
"routePath": "unsaved-changes",
|
|
460
|
+
"importPath": "ngx-oneforall/guards/unsaved-changes",
|
|
461
|
+
"url": "https://love1024.github.io/ngx-oneforall/guards/unsaved-changes",
|
|
462
|
+
"description": "Unsaved changes guards are essential for protecting users from accidentally losing their work when navigating away from a page with unsaved modifications. This guard leverages the native window.confirm dialog to prompt the user for confirmation.",
|
|
463
|
+
"fullContent": "Unsaved changes guards are essential for protecting users from accidentally losing their work when navigating away from a page with unsaved modifications. This guard leverages the native `window.confirm` dialog to prompt the user for confirmation.\n\n#### How to Use\n\n1. **Import the Guard**\n Import `unsavedChangesGuard` and the `HasUnsavedChanges` interface:\n ```typescript\n import { HasUnsavedChanges, unsavedChangesGuard } from 'ngx-oneforall/guards/unsaved-changes';\n ```\n\n2. **Register the Guard**\n Add the guard to your route configuration using `canDeactivate`:\n ```typescript {4}\n {\n path: 'form',\n canDeactivate: [\n unsavedChangesGuard()\n ]\n }\n ```\n\n3. **Implement the Interface**\n Implement `HasUnsavedChanges` in your component:\n ```typescript\n export class UnsavedChangesDemoComponent implements HasUnsavedChanges {\n // ...\n hasUnsavedChanges() {\n return this.form.dirty;\n }\n }\n ```\n\n4. **Async Checks (Optional)**\n The `hasUnsavedChanges` method can return a `boolean`, `Promise<boolean>`, or `Observable<boolean>`.\n \n ```typescript\n hasUnsavedChanges(): Observable<boolean> {\n return this.apiClient.checkDraftStatus().pipe(\n map(status => status.hasChanges)\n );\n }\n ```\n\n#### Use Cases\n- Preventing navigation away from a form with unsaved data.\n- Alerting users before closing a tab or browser window if changes haven't been saved.\n- Guarding against accidental loss of progress in multi-step wizards or editors.\n\n#### Live Demo\n\n> **Note**\n> This demo manually triggers the guard check to show the confirmation dialog. In a real routing scenario, this would happen automatically before navigation.\n\n\n\n\n#### Customizing the Confirmation Message\nYou can customize the message displayed in the confirmation dialog by passing a string to the factory function.\n\n```typescript {4}\n {\n path: 'form',\n canDeactivate: [\n unsavedChangesGuard('You have unsaved work! Are you sure you want to leave?')\n ]\n }\n```"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"name": "Base URL Interceptor",
|
|
467
|
+
"category": "interceptors",
|
|
468
|
+
"categoryTitle": "Interceptors",
|
|
469
|
+
"dirName": "base-url",
|
|
470
|
+
"routePath": "base-url",
|
|
471
|
+
"importPath": "ngx-oneforall/interceptors/base-url",
|
|
472
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/base-url",
|
|
473
|
+
"description": "The withBaseUrlInterceptor is an Angular HTTP interceptor that automatically prepends a base URL to all relative HTTP requests. It eliminates repetitive URL construction across your application.",
|
|
474
|
+
"fullContent": "The `withBaseUrlInterceptor` is an Angular HTTP interceptor that automatically prepends a base URL to all relative HTTP requests. It eliminates repetitive URL construction across your application.\n\n## Features\n\n- **Single configuration point** — Define your API base URL once\n- **Relative paths** — Use `/users` instead of `https://api.example.com/users`\n- **Dynamic URLs** — Support for functions that resolve URLs at runtime\n- **Path-specific overrides** — Route different paths to different base URLs\n- **Per-request control** — Disable or override via `HttpContext`\n- **Smart slash handling** — Automatically normalizes trailing/leading slashes\n\n## Installation\n\n```typescript\nimport { withBaseUrlInterceptor } from 'ngx-oneforall/interceptors/base-url';\n```\n\n## Quick Start\n\n### Standalone Applications\n\n```typescript\nimport { provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { withBaseUrlInterceptor } from 'ngx-oneforall/interceptors/base-url';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHttpClient(\n withInterceptors([\n withBaseUrlInterceptor({ baseUrl: 'https://api.example.com' })\n ])\n ),\n ],\n};\n```\n\n### NgModule Applications\n\n```typescript\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { withBaseUrlInterceptor } from 'ngx-oneforall/interceptors/base-url';\n\n@NgModule({\n providers: [\n { \n provide: HTTP_INTERCEPTORS, \n useValue: withBaseUrlInterceptor({ baseUrl: 'https://api.example.com' }), \n multi: true \n }\n ]\n})\nexport class AppModule {}\n```\n\n### Making Requests\n\n```typescript\n// Before (without interceptor)\nthis.http.get('https://api.example.com/users');\n\n// After (with interceptor)\nthis.http.get('/users'); // → https://api.example.com/users\n```\n\n## Configuration\n\n### BaseUrlConfig\n\n| Property | Type | Required | Description |\n|----------|------|----------|-------------|\n| `baseUrl` | `string \\| (() => string)` | **Yes** | Default base URL for all relative requests |\n| `overrides` | `BaseUrlOverrides[]` | No | Path-specific base URL overrides |\n\n### BaseUrlOverrides\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `startWith` | `string` | Path prefix to match (e.g., `'auth'`, `'api/v2'`) |\n| `url` | `string \\| (() => string)` | Base URL to use when prefix matches |\n\n> **Warning**\n> The `baseUrl` option is required. The interceptor throws an error if not provided.\n\n## Behavior\n\n### Processing Order\n\nThe interceptor processes requests in the following order:\n\n1. **Check context** — If disabled via `HttpContext`, pass through unchanged\n2. **Check absolute URL** — If the request URL starts with `http://` or `https://`, pass through unchanged\n3. **Resolve base URL** — Use context override, matching path override, or default `baseUrl`\n4. **Join URLs** — Combine base URL and request path with proper slash handling\n\n### Smart Slash Handling\n\nThe interceptor automatically normalizes slashes between the base URL and path:\n\n```typescript\n// All produce: https://api.example.com/users\n\nwithBaseUrlInterceptor({ baseUrl: 'https://api.example.com/' })\nthis.http.get('/users') // trailing + leading slash\n\nwithBaseUrlInterceptor({ baseUrl: 'https://api.example.com' })\nthis.http.get('users') // no slashes\n\nwithBaseUrlInterceptor({ baseUrl: 'https://api.example.com/' })\nthis.http.get('users') // trailing slash only\n```\n\n### Absolute URLs Pass Through\n\nRequests with absolute URLs are never modified:\n\n```typescript\nthis.http.get('/users'); // → https://api.example.com/users\nthis.http.get('https://other-api.com/data'); // → https://other-api.com/data (unchanged)\n```\n\n## Context API\n\nControl the interceptor on a per-request basis using `useBaseUrl`:\n\n```typescript\nimport { useBaseUrl } from 'ngx-oneforall/interceptors/base-url';\n```\n\n### Disable for a Request\n\n```typescript\nthis.http.get('https://external-api.com/data', {\n context: useBaseUrl({ enabled: false })\n});\n```\n\n### Override Base URL\n\n```typescript\nthis.http.get('/admin/settings', {\n context: useBaseUrl({ baseUrl: 'https://admin-api.example.com' })\n});\n```\n\n### Context Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `enabled` | `boolean` | Set `false` to skip base URL prepending |\n| `baseUrl` | `string \\| (() => string)` | Override the configured base URL |\n| `context` | `HttpContext` | Extend an existing `HttpContext` |\n\n## Examples\n\n### Environment-Based Configuration\n\n```typescript\n// environments/environment.ts\nexport const environment = {\n production: false,\n apiUrl: 'http://localhost:3000'\n};\n\n// environments/environment.prod.ts\nexport const environment = {\n production: true,\n apiUrl: 'https://api.production.com'\n};\n\n// app.config.ts\nimport { environment } from './environments/environment';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHttpClient(\n withInterceptors([\n withBaseUrlInterceptor({ baseUrl: environment.apiUrl })\n ])\n ),\n ],\n};\n```\n\n### Dynamic URL with Dependency Injection\n\nUse a function to resolve the base URL dynamically in the injection context:\n\n```typescript\nimport { inject, InjectionToken } from '@angular/core';\n\nexport const API_URL = new InjectionToken<string>('API_URL');\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n { provide: API_URL, useValue: 'https://api.example.com' },\n provideHttpClient(\n withInterceptors([\n withBaseUrlInterceptor({\n baseUrl: () => inject(API_URL)\n })\n ])\n ),\n ],\n};\n```\n\n### Path-Specific Overrides\n\nRoute specific path prefixes to different base URLs:\n\n```typescript\nwithBaseUrlInterceptor({\n baseUrl: 'https://api.example.com',\n overrides: [\n { startWith: 'auth', url: 'https://auth.example.com' },\n { startWith: 'api/v2', url: 'https://api-v2.example.com' },\n { startWith: 'assets', url: () => inject(ASSETS_URL) }\n ]\n})\n```\n\n**Matching behavior:**\n- `/auth/login` → `https://auth.example.com/auth/login`\n- `/api/v2/users` → `https://api-v2.example.com/api/v2/users`\n- `/users` → `https://api.example.com/users`\n\n> **Note**\n> Overrides are matched in array order. The first matching prefix wins.\n\n### Mixed API Endpoints\n\n```typescript\n// Default: all requests use https://api.example.com\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHttpClient(\n withInterceptors([\n withBaseUrlInterceptor({ baseUrl: 'https://api.example.com' })\n ])\n ),\n ],\n};\n\n// Override for specific requests\n@Injectable()\nclass AnalyticsService {\n constructor(private http: HttpClient) {}\n\n trackEvent(event: string) {\n return this.http.post('/events', { event }, {\n context: useBaseUrl({ baseUrl: 'https://analytics.example.com' })\n });\n }\n}\n```\n\n## Demo\n\nExplore a live demonstration of the base URL interceptor:"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"name": "Cache Interceptor",
|
|
478
|
+
"category": "interceptors",
|
|
479
|
+
"categoryTitle": "Interceptors",
|
|
480
|
+
"dirName": "cache",
|
|
481
|
+
"routePath": "cache",
|
|
482
|
+
"importPath": "ngx-oneforall/interceptors/cache",
|
|
483
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/cache",
|
|
484
|
+
"description": "The withCacheInterceptor caches HTTP responses to improve performance.",
|
|
485
|
+
"fullContent": "The `withCacheInterceptor` caches HTTP responses to improve performance.\n\n## Features\n\n- **Two strategies** — Auto (all GETs) or manual (per-request)\n- **Multiple storage** — Memory, localStorage, or sessionStorage\n- **TTL support** — Configurable time-to-live\n- **Version invalidation** — Bust cache on version change\n- **SSR-safe** — Skips caching on server\n\n## Installation\n\n```typescript\nimport { withCacheInterceptor } from 'ngx-oneforall/interceptors/cache';\n```\n\n## Quick Start\n\n```typescript\nprovideHttpClient(\n withInterceptors([\n withCacheInterceptor({ strategy: 'auto' })\n ])\n);\n```\n\n## Configuration\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `strategy` | `'auto' \\| 'manual'` | `'manual'` | Auto caches all GETs, manual requires context |\n| `storage` | `'memory' \\| 'local' \\| 'session'` | `'memory'` | Default storage backend |\n| `ttl` | `number` | `3600000` | Default TTL in milliseconds (1 hour) |\n| `storagePrefix` | `string` | — | Key prefix for storage |\n| `version` | `string` | — | Cache version for invalidation |\n| `cacheBust` | `(req) => boolean \\| void` | — | Function for cache invalidation. Return `true` to clear cache. |\n\n## Strategies\n\n### Auto Strategy\n\nCaches all GET requests with JSON response type automatically:\n\n```typescript\nwithCacheInterceptor({ strategy: 'auto' })\n```\n\n### Manual Strategy (Default)\n\nOnly caches requests with explicit context:\n\n```typescript\nimport { useCache } from 'ngx-oneforall/interceptors/cache';\n\nthis.http.get('/api/data', {\n context: useCache()\n});\n```\n\n## Cache Invalidation (Cache Bust)\n\nYou can provide a `cacheBust` function to implement custom cache invalidation logic. This function runs in the injection context, so you can use `inject()`. Return `true` to automatically clear the entire cache.\n\n```typescript\nwithCacheInterceptor({\n cacheBust: (req) => {\n // Automatically clear cache on logout\n if (req.url.includes('/logout')) {\n return true;\n }\n }\n})\n```\n\n## Per-Request Options\n\n```typescript\nthis.http.get('/api/data', {\n context: useCache({\n enabled: true,\n key: 'custom-key',\n ttl: 60000,\n storage: 'session'\n })\n});\n```\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `enabled` | `boolean` | Enable/disable caching for this request |\n| `key` | `string \\| (req) => string` | Custom cache key |\n| `ttl` | `number` | TTL override for this request |\n| `storage` | `'memory' \\| 'local' \\| 'session'` | Storage override |\n\n## Dynamic Cache Keys\n\n```typescript\nthis.http.get('/api/users', {\n context: useCache({\n key: req => `users-${req.params.get('page')}`\n })\n});\n```\n\n## Demo"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"name": "Correlation ID Interceptor",
|
|
489
|
+
"category": "interceptors",
|
|
490
|
+
"categoryTitle": "Interceptors",
|
|
491
|
+
"dirName": "correlation-id",
|
|
492
|
+
"routePath": "correlation-id",
|
|
493
|
+
"importPath": "ngx-oneforall/interceptors/correlation-id",
|
|
494
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/correlation-id",
|
|
495
|
+
"description": "The withCorrelationIdInterceptor is an Angular HTTP interceptor that automatically adds a unique correlation ID header to each HTTP request. It enables request tracking, debugging, and distributed tracing across services.",
|
|
496
|
+
"fullContent": "The `withCorrelationIdInterceptor` is an Angular HTTP interceptor that automatically adds a unique correlation ID header to each HTTP request. It enables request tracking, debugging, and distributed tracing across services.\n\n## Features\n\n- **Automatic ID generation** — Unique ID added to every request\n- **Distributed tracing** — Track requests across microservices\n- **Custom header name** — Use your own header (default: `X-Correlation-Id`)\n- **Custom ID generator** — Provide your own ID generation logic\n- **Per-request control** — Disable or override via `HttpContext`\n- **SSR-compatible** — Works on both server and browser\n\n## Installation\n\n```typescript\nimport { withCorrelationIdInterceptor } from 'ngx-oneforall/interceptors/correlation-id';\n```\n\n## Quick Start\n\n### Standalone Applications\n\n```typescript\nimport { provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { withCorrelationIdInterceptor } from 'ngx-oneforall/interceptors/correlation-id';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHttpClient(\n withInterceptors([withCorrelationIdInterceptor()])\n ),\n ],\n};\n```\n\n### NgModule Applications\n\n```typescript\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { withCorrelationIdInterceptor } from 'ngx-oneforall/interceptors/correlation-id';\n\n@NgModule({\n providers: [\n { \n provide: HTTP_INTERCEPTORS, \n useValue: withCorrelationIdInterceptor(), \n multi: true \n }\n ]\n})\nexport class AppModule {}\n```\n\n### Result\n\nEvery request automatically includes a correlation ID:\n\n```\nGET /api/users\nX-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000\n```\n\n## Configuration\n\n### CorrelationIdConfig\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `header` | `string` | `'X-Correlation-Id'` | Header name for the correlation ID |\n| `idGenerator` | `() => string` | `crypto.randomUUID()` | Function to generate unique IDs |\n\n### Custom Header Name\n\n```typescript\nwithCorrelationIdInterceptor({\n header: 'X-Request-Id'\n})\n```\n\n### Custom ID Generator\n\n```typescript\nwithCorrelationIdInterceptor({\n idGenerator: () => `req-${Date.now()}-${Math.random().toString(16).slice(2)}`\n})\n```\n\n### Default ID Generator\n\nUses `crypto.randomUUID()` when available, with a fallback for older browsers:\n\n```typescript\ncrypto.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(16).slice(2)}`\n```\n\n## Behavior\n\n### Processing Order\n\nThe interceptor processes requests in the following order:\n\n1. **Check context** — If disabled via `HttpContext`, pass through\n2. **Check existing header** — If header already present, don't override\n3. **Add correlation ID** — Use context ID, or generate a new one\n\n### SSR Support\n\nThe interceptor is fully compatible with server-side rendering (SSR) and will add correlation IDs to requests made on the server.\n\n### Existing Headers Preserved\n\nIf a request already has the correlation ID header, it won't be overridden:\n\n```typescript\n// Manual header takes precedence\nthis.http.get('/api/data', {\n headers: { 'X-Correlation-Id': 'my-custom-id' }\n});\n```\n\n## Context API\n\nControl the interceptor on a per-request basis using `useCorrelationId`:\n\n```typescript\nimport { useCorrelationId } from 'ngx-oneforall/interceptors/correlation-id';\n```\n\n### Disable for a Request\n\n```typescript\nthis.http.get('/api/public', {\n context: useCorrelationId({ enabled: false })\n});\n```\n\n### Use a Specific ID\n\n```typescript\nthis.http.post('/api/checkout', cart, {\n context: useCorrelationId({ id: 'checkout-flow-12345' })\n});\n```\n\n### Context Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `enabled` | `boolean` | Set `false` to skip adding correlation ID |\n| `id` | `string` | Use a specific ID instead of generating one |\n| `context` | `HttpContext` | Extend an existing `HttpContext` |\n\n## Examples\n\n### Distributed Tracing\n\nTrack requests across your entire system:\n\n```typescript\n// Frontend sends request\nthis.http.get('/api/orders/123').subscribe();\n// Header: X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000\n\n// Backend logs with the same ID\n// [550e8400-...] API Gateway: Received request\n// [550e8400-...] Order Service: Fetching order 123\n// [550e8400-...] Database: Query executed in 15ms\n```\n\n### User-Scoped IDs\n\nInclude user context in correlation IDs:\n\n```typescript\nwithCorrelationIdInterceptor({\n idGenerator: () => {\n const userId = inject(AuthService).userId();\n return `${userId}-${crypto.randomUUID()}`;\n }\n})\n```\n\n### Action Tracking\n\nTrack specific user actions:\n\n```typescript\nconst checkoutId = `checkout-${crypto.randomUUID()}`;\n\n// All checkout-related requests share the same correlation ID\nthis.http.post('/api/validate-cart', cart, {\n context: useCorrelationId({ id: checkoutId })\n});\n\nthis.http.post('/api/process-payment', payment, {\n context: useCorrelationId({ id: checkoutId })\n});\n\nthis.http.post('/api/create-order', order, {\n context: useCorrelationId({ id: checkoutId })\n});\n```\n\n### Multiple Header Formats\n\nDifferent backend services may expect different headers:\n\n```typescript\n// For AWS X-Ray\nwithCorrelationIdInterceptor({ header: 'X-Amzn-Trace-Id' });\n\n// For Zipkin\nwithCorrelationIdInterceptor({ header: 'X-B3-TraceId' });\n\n// For custom systems\nwithCorrelationIdInterceptor({ header: 'X-Request-Id' });\n```\n\n## Demo\n\nExplore a live demonstration of the correlation ID interceptor:"
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"name": "Encryption Interceptor",
|
|
500
|
+
"category": "interceptors",
|
|
501
|
+
"categoryTitle": "Interceptors",
|
|
502
|
+
"dirName": "encryption",
|
|
503
|
+
"routePath": "encryption",
|
|
504
|
+
"importPath": "ngx-oneforall/interceptors/encryption",
|
|
505
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/encryption",
|
|
506
|
+
"description": "The withEncryptionInterceptor encrypts request bodies and decrypts response bodies using a configurable adapter.",
|
|
507
|
+
"fullContent": "The `withEncryptionInterceptor` encrypts request bodies and decrypts response bodies using a configurable adapter.\n\n## Features\n\n- **Pluggable adapters** — Use any encryption library (CryptoJS, Web Crypto, etc.)\n- **Bidirectional** — Encrypt requests and decrypt responses\n- **Per-request control** — Disable via `HttpContext`\n- **Error handling** — Configurable throw behavior on encryption/decryption errors\n- **Header indication** — Adds header to indicate encrypted content\n\n## Installation\n\n```typescript\nimport { withEncryptionInterceptor, EncryptionAdapter } from 'ngx-oneforall/interceptors/encryption';\n```\n\n## Quick Start\n\n### Create an Adapter\n\n```typescript\nconst adapter: EncryptionAdapter = {\n encrypt: (data) => btoa(JSON.stringify(data)),\n decrypt: (data) => JSON.parse(atob(data as string))\n};\n```\n\n### Register Interceptor\n\n```typescript\nprovideHttpClient(\n withInterceptors([\n withEncryptionInterceptor({ adapter })\n ])\n);\n```\n\n## Configuration\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `adapter` | `EncryptionAdapter` | **Required** | Encrypt/decrypt implementation |\n| `enabled` | `boolean` | `true` | Enable encryption globally |\n| `headerName` | `string` | `'X-Encrypted-Data'` | Header name for encrypted requests |\n| `headerValue` | `string` | `'1'` | Header value when encrypted |\n| `throwOnEncryptionError` | `boolean` | `true` | Throw if encryption fails |\n| `throwOnDecryptionError` | `boolean` | `true` | Throw if decryption fails |\n\n### EncryptionAdapter Interface\n\n```typescript\ninterface EncryptionAdapter<T = unknown, E = unknown> {\n encrypt(data: T): E;\n decrypt(data: E): T;\n}\n```\n\n## Error Handling\n\nBy default, errors during encryption/decryption are thrown. Set to `false` to fail silently:\n\n```typescript\nwithEncryptionInterceptor({\n adapter,\n throwOnEncryptionError: false, // Send unencrypted on failure\n throwOnDecryptionError: false // Return raw response on failure\n});\n```\n\n## Context API\n\n```typescript\nimport { useEncryption } from 'ngx-oneforall/interceptors/encryption';\n```\n\n### Disable for a Request\n\n```typescript\nthis.http.post('/api/public', data, {\n context: useEncryption({ enabled: false })\n});\n```\n\n### Encrypt Only (No Decryption)\n\n```typescript\nthis.http.post('/api/data', payload, {\n context: useEncryption({ decryptResponse: false })\n});\n```\n\n### Context Options\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `enabled` | `boolean` | `true` | Enable/disable encryption |\n| `encryptRequest` | `boolean` | `true` | Encrypt request body |\n| `decryptResponse` | `boolean` | `true` | Decrypt response body |\n| `context` | `HttpContext` | — | Extend existing context |\n\n## Examples\n\n### AES Encryption with CryptoJS\n\n```typescript\nimport * as CryptoJS from 'crypto-js';\n\nconst aesAdapter: EncryptionAdapter = {\n encrypt: (data) => CryptoJS.AES.encrypt(JSON.stringify(data), SECRET).toString(),\n decrypt: (data) => JSON.parse(\n CryptoJS.AES.decrypt(data as string, SECRET).toString(CryptoJS.enc.Utf8)\n )\n};\n```\n\n### Selective Encryption\n\n```typescript\n// Encrypt sensitive endpoints\nthis.http.put('/api/profile', profile); // Encrypted\n\n// Skip for public endpoints\nthis.http.get('/api/public', {\n context: useEncryption({ enabled: false }) // Not encrypted\n});\n```\n\n> **Note**\n> Always use HTTPS in addition to application-layer encryption.\n\n> **Warning**\n> The demo uses Base64 encoding for simplicity, which is NOT encryption. Use proper cryptographic algorithms in production.\n\n## Demo"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"name": "Jwt Interceptor",
|
|
511
|
+
"category": "interceptors",
|
|
512
|
+
"categoryTitle": "Interceptors",
|
|
513
|
+
"dirName": "jwt",
|
|
514
|
+
"routePath": "jwt",
|
|
515
|
+
"importPath": "ngx-oneforall/interceptors/jwt",
|
|
516
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/jwt",
|
|
517
|
+
"description": "The withJwtInterceptor attaches JWT tokens to outgoing HTTP requests for allowed domains.",
|
|
518
|
+
"fullContent": "The `withJwtInterceptor` attaches JWT tokens to outgoing HTTP requests for allowed domains.\n\n## Features\n\n- **Automatic token attachment** — Add JWT to requests automatically\n- **Domain filtering** — Only attach tokens to allowed domains\n- **Route exclusions** — Skip specific URLs\n- **Token refresh (optional)** — Handle 401 errors with automatic refresh\n- **Per-request control** — Disable via `HttpContext`\n- **SSR-safe** — Skips on server-side rendering\n\n## Installation\n\n```typescript\nimport { withJwtInterceptor } from 'ngx-oneforall/interceptors/jwt';\n```\n\n## Quick Start\n\n```typescript\nprovideHttpClient(\n withInterceptors([\n withJwtInterceptor({\n tokenGetter: () => localStorage.getItem('access_token')\n })\n ])\n);\n```\n\n## Configuration\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `tokenGetter` | `() => string \\| null` | **Required** | Function that returns the JWT |\n| `authScheme` | `string` | `'Bearer '` | Prefix for the token |\n| `headerName` | `string` | `'Authorization'` | Header name for the token |\n| `allowedDomains` | `(string \\| RegExp)[]` | `[]` | Domains to receive the token (empty = all allowed) |\n| `skipUrls` | `(string \\| RegExp)[]` | `[]` | URLs to exclude from token attachment |\n| `skipAddingIfExpired` | `boolean` | `false` | Skip if token is expired |\n| `errorOnNoToken` | `boolean` | `false` | Throw if no token available |\n| `refreshTokenHandler` | `RefreshTokenHandler` | — | Handler for automatic token refresh |\n\n> **Note**\n> The current origin (`document.location.origin`) is always allowed, even if not in `allowedDomains`.\n\n## Token Refresh\n\nHandle 401 errors with automatic token refresh:\n\n```typescript\nwithJwtInterceptor({\n tokenGetter: () => localStorage.getItem('token'),\n refreshTokenHandler: {\n refreshToken: () => authService.refresh(),\n logout: () => router.navigate(['/login'])\n }\n});\n```\n\n### RefreshTokenHandler Interface\n\n```typescript\ninterface RefreshTokenHandler {\n refreshToken(): Observable<string>;\n logout(): void;\n}\n```\n\n### Refresh Behavior\n\n- **Automatic retry** — Failed requests retry with new token\n- **Deduplication** — Multiple 401s trigger only one refresh\n- **Logout on failure** — Calls `logout()` if refresh fails\n- **No handler = no refresh** — 401 errors propagate as-is\n\n## Context API\n\n```typescript\nimport { withSkipJwtInterceptor } from 'ngx-oneforall/interceptors/jwt';\n```\n\n### Skip for a Request\n\nBypass the interceptor for specific requests:\n\n```typescript\n// Skip for login request\nthis.http.post('/api/login', credentials, {\n context: withSkipJwtInterceptor()\n});\n\n// Skip for refresh token request\nthis.http.post('/api/auth/refresh', {}, {\n context: withSkipJwtInterceptor()\n});\n```\n\n## Examples\n\n### Basic Setup\n\n```typescript\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHttpClient(\n withInterceptors([\n withJwtInterceptor({\n tokenGetter: () => localStorage.getItem('access_token')\n })\n ])\n )\n ]\n};\n```\n\n### Domain Filtering\n\n```typescript\nwithJwtInterceptor({\n tokenGetter: () => localStorage.getItem('token'),\n allowedDomains: [\n 'api.example.com',\n 'api-v2.example.com',\n /.*\\.example\\.com/ // Regex for subdomains\n ]\n});\n```\n\n### Exclude Routes\n\n```typescript\nwithJwtInterceptor({\n tokenGetter: () => localStorage.getItem('token'),\n skipUrls: [\n '/api/public',\n /\\/api\\/auth\\/.*/ // Skip all auth routes\n ]\n});\n```\n\n### Full Configuration\n\n```typescript\nwithJwtInterceptor({\n tokenGetter: () => localStorage.getItem('access_token'),\n authScheme: 'Bearer ',\n headerName: 'Authorization',\n allowedDomains: ['api.example.com'],\n skipUrls: ['/api/public'],\n skipAddingIfExpired: true,\n errorOnNoToken: false,\n refreshTokenHandler: {\n refreshToken: () => this.authService.refresh().pipe(\n tap(token => localStorage.setItem('access_token', token))\n ),\n logout: () => {\n localStorage.clear();\n this.router.navigate(['/login']);\n }\n }\n});\n```"
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"name": "Performance Interceptor",
|
|
522
|
+
"category": "interceptors",
|
|
523
|
+
"categoryTitle": "Interceptors",
|
|
524
|
+
"dirName": "performance",
|
|
525
|
+
"routePath": "performance",
|
|
526
|
+
"importPath": "ngx-oneforall/interceptors/performance",
|
|
527
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/performance",
|
|
528
|
+
"description": "The withPerformanceInterceptor measures and reports HTTP request performance automatically.",
|
|
529
|
+
"fullContent": "The `withPerformanceInterceptor` measures and reports HTTP request performance automatically.\n\n## Features\n\n- **Automatic timing** — Measures all HTTP requests\n- **Slow detection** — Mark requests exceeding a threshold\n- **Report control** — Only report slow requests if needed\n- **Per-request control** — Disable or label via `HttpContext`\n- **SSR-safe** — Falls back to `Date.now()` on server\n\n## Installation\n\n```typescript\nimport { withPerformanceInterceptor } from 'ngx-oneforall/interceptors/performance';\n```\n\n## Quick Start\n\n```typescript\nprovideHttpClient(\n withInterceptors([\n withPerformanceInterceptor()\n ])\n);\n```\n\n## Configuration\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `enabled` | `boolean` | `true` | Enable/disable reporting globally |\n| `reporter` | `(entry) => void` | `console.debug` | Custom handler for performance entries |\n| `slowThresholdMs` | `number` | — | Mark requests exceeding this duration as slow |\n| `reportOnlyIfSlow` | `boolean` | `false` | Only report requests that exceed `slowThresholdMs` |\n\n## PerformanceEntry\n\n```typescript\ninterface PerformanceEntry {\n url: string; // Request URL\n method: string; // HTTP method\n durationMs: number; // Duration in milliseconds\n status?: number; // HTTP status code\n label?: string; // Custom label\n isSlow?: boolean; // Exceeded slow threshold\n}\n```\n\n## Custom Reporter\n\nReporters run in Angular's injection context, allowing `inject()`:\n\n```typescript\nwithPerformanceInterceptor({\n reporter: entry => {\n const analytics = inject(AnalyticsService);\n analytics.track('http_request', entry);\n }\n});\n```\n\n## Slow Request Detection\n\nMark and optionally filter slow requests:\n\n```typescript\nwithPerformanceInterceptor({\n slowThresholdMs: 2000, // 2 seconds\n reportOnlyIfSlow: true // Only report slow requests\n});\n```\n\nThe default reporter prefixes slow requests with `[HTTP Performance - SLOW]`.\n\n## Context API\n\n```typescript\nimport { usePerformance } from 'ngx-oneforall/interceptors/performance';\n```\n\n### Disable for a Request\n\n```typescript\nthis.http.get('/api/health', {\n context: usePerformance({ enabled: false })\n});\n```\n\n### Add Custom Label\n\n```typescript\nthis.http.post('/api/checkout', cart, {\n context: usePerformance({ label: 'Checkout Flow' })\n});\n```\n\n### Context Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `enabled` | `boolean` | Disable reporting for this request |\n| `label` | `string` | Custom label for identification |\n| `context` | `HttpContext` | Existing context to extend |\n\n## Examples\n\n### Alert on Slow Requests\n\n```typescript\nwithPerformanceInterceptor({\n slowThresholdMs: 2000,\n reporter: entry => {\n if (entry.isSlow) {\n const toast = inject(ToastService);\n toast.warn(`Slow: ${entry.url} took ${entry.durationMs}ms`);\n }\n }\n});\n```\n\n### Analytics Integration\n\n```typescript\nwithPerformanceInterceptor({\n reporter: entry => {\n const analytics = inject(AnalyticsService);\n analytics.track('performance', {\n url: entry.url,\n duration: entry.durationMs,\n status: entry.status,\n slow: entry.isSlow\n });\n }\n});\n```\n\n### Production Slow-Only Monitoring\n\n```typescript\nwithPerformanceInterceptor({\n slowThresholdMs: 3000,\n reportOnlyIfSlow: true,\n reporter: entry => {\n const logger = inject(LoggingService);\n logger.warn('Slow request', entry);\n }\n});\n```\n\n## Demo"
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
"name": "Timeout Interceptor",
|
|
533
|
+
"category": "interceptors",
|
|
534
|
+
"categoryTitle": "Interceptors",
|
|
535
|
+
"dirName": "timeout",
|
|
536
|
+
"routePath": "timeout",
|
|
537
|
+
"importPath": "ngx-oneforall/interceptors/timeout",
|
|
538
|
+
"url": "https://love1024.github.io/ngx-oneforall/interceptors/timeout",
|
|
539
|
+
"description": "The withTimeoutInterceptor adds automatic timeouts to HTTP requests.",
|
|
540
|
+
"fullContent": "The `withTimeoutInterceptor` adds automatic timeouts to HTTP requests.\n\n## Features\n\n- **Default timeout** — Apply timeout to all requests\n- **Per-request override** — Context API for custom timeouts\n- **Structured errors** — Typed error with request metadata\n\n## Installation\n\n```typescript\nimport { withTimeoutInterceptor } from 'ngx-oneforall/interceptors/timeout';\n```\n\n## Quick Start\n\n```typescript\nprovideHttpClient(\n withInterceptors([\n withTimeoutInterceptor(30000) // 30 second default\n ])\n);\n```\n\n## Per-Request Timeout\n\nOverride the default timeout for specific requests:\n\n```typescript\nimport { withTimeout } from 'ngx-oneforall/interceptors/timeout';\n\nthis.http.get('/api/slow-endpoint', {\n context: withTimeout({ timeout: 60000 }) // 60 seconds\n});\n```\n\n## Error Handling\n\n```typescript\nimport { TIMEOUT_ERROR } from 'ngx-oneforall/interceptors/timeout';\n\nthis.http.get('/api/data').pipe(\n catchError(error => {\n if (error.name === TIMEOUT_ERROR) {\n console.error('Request timed out:', error.message);\n }\n return throwError(() => error);\n })\n);\n```\n\n### TimeoutErrorInfo\n\n```typescript\ninterface TimeoutErrorInfo {\n name: 'TimeoutError'; // Always 'TimeoutError'\n message: string; // 'Request timed out after Xms'\n request: HttpRequest<unknown>; // Original request\n}\n```\n\n## Demo"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"name": "Bytes Pipe",
|
|
544
|
+
"category": "pipes",
|
|
545
|
+
"categoryTitle": "Pipes",
|
|
546
|
+
"dirName": "bytes",
|
|
547
|
+
"routePath": "bytes",
|
|
548
|
+
"importPath": "ngx-oneforall/pipes/bytes",
|
|
549
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/bytes",
|
|
550
|
+
"description": "The BytesPipe converts a number (in bytes) into a human-readable string with appropriate units (B, KB, MB, GB, TB, PB). It automatically selects the best unit and formats the number with configurable decimal places.",
|
|
551
|
+
"fullContent": "The `BytesPipe` converts a number (in bytes) into a human-readable string with appropriate units (B, KB, MB, GB, TB, PB). It automatically selects the best unit and formats the number with configurable decimal places.\n\n### Installation\n\n```ts\nimport { BytesPipe } from 'ngx-oneforall/pipes/bytes';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L4\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `value` | `number \\| string` | — | The bytes value to format |\n| `decimals` | `number` | `2` | Decimal places in output |\n| `units` | `string[] \\| null` | `['B', 'KB', ...]` | Custom unit labels |\n| `useSI` | `boolean` | `false` | Use SI base (1000) instead of binary (1024) |\n\n### Binary vs SI Units\n\nBy default, the pipe uses **binary** base (1024):\n- 1 KB = 1024 bytes\n- 1 MB = 1,048,576 bytes\n\nWith `useSI: true`, use **SI** base (1000):\n- 1 KB = 1000 bytes\n- 1 MB = 1,000,000 bytes\n\n```html file=\"./snippets.html\"#L22-L24\n```\n\n### Examples\n\n#### Custom Decimals\n\n```html file=\"./snippets.html\"#L8-L10\n```\n\n#### Custom Units\n\n```html file=\"./snippets.html\"#L18-L18\n```\n\n#### Large Numbers\n\n```html file=\"./snippets.html\"#L14-L14\n```\n\n### Edge Cases\n\n- Handles negative numbers: `-1024` → `-1.00 KB`\n- Returns `0 B` for invalid values (`NaN`, `null`, `undefined`, empty string)\n- Caps at largest unit for very large numbers\n\n---\n\n#### Live Demo"
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
"name": "Call Pipe",
|
|
555
|
+
"category": "pipes",
|
|
556
|
+
"categoryTitle": "Pipes",
|
|
557
|
+
"dirName": "call",
|
|
558
|
+
"routePath": "call",
|
|
559
|
+
"importPath": "ngx-oneforall/pipes/call",
|
|
560
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/call",
|
|
561
|
+
"description": "The CallPipe invokes a function directly from the template with pure pipe caching. This prevents unnecessary change detection cycles since the function is only re-evaluated when its reference or arguments change.",
|
|
562
|
+
"fullContent": "The `CallPipe` invokes a function directly from the template with pure pipe caching. This prevents unnecessary change detection cycles since the function is only re-evaluated when its reference or arguments change.\n\n### Installation\n\n```ts\nimport { CallPipe } from 'ngx-oneforall/pipes/call';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L2\n```\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `fn` | `Function` | The function to call |\n| `...args` | `unknown[]` | Arguments to pass to the function |\n\n### Why Use CallPipe?\n\nWithout the pipe, functions in templates are called on every change detection:\n\n```html\n<!-- ❌ Called on every CD cycle -->\n{% raw %}{% endraw %}\n\n<!-- ✅ Called only when date changes -->\n{% raw %}{% endraw %}\n```\n\n### Preserving Context\n\nWhen using methods that rely on `this`, ensure the context is preserved:\n\n#### Arrow Functions (Recommended)\n\nArrow functions automatically capture `this`:\n\n```html file=\"./snippets.html\"#L6-L6\n```\n\n#### Bound Methods\n\nFor regular methods, bind explicitly:\n\n```typescript\n// In component\ngetCounterBound = this.getCounter.bind(this);\n```\n\n```html file=\"./snippets.html\"#L10-L10\n```\n\n### Behavior\n\n- **Pure** - Only re-evaluates when function reference or arguments change\n- **Type-safe** - Generic typing for better type inference\n- **Null-safe** - Returns `null` if input is not a function\n\n---\n\n#### Live Demo"
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
"name": "First Error Key",
|
|
566
|
+
"category": "pipes",
|
|
567
|
+
"categoryTitle": "Pipes",
|
|
568
|
+
"dirName": "first-error-key",
|
|
569
|
+
"routePath": "first-error-key",
|
|
570
|
+
"importPath": "ngx-oneforall/pipes/first-error-key",
|
|
571
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/first-error-key",
|
|
572
|
+
"description": "The FirstErrorKeyPipe extracts the first validation error key from a form control's errors. It supports optional priority ordering to control which error displays first.",
|
|
573
|
+
"fullContent": "The `FirstErrorKeyPipe` extracts the first validation error key from a form control's errors. It supports optional priority ordering to control which error displays first.\n\n### Installation\n\n```ts\nimport { FirstErrorKeyPipe } from 'ngx-oneforall/pipes/first-error-key';\n```\n\n### Usage\n\n```html file=\"./demo/snippets.html\"#L4-L6\n```\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `errors` | `ValidationErrors \\| null` | Errors object from a form control |\n| `priority` | `string[]` | Optional array of error keys in priority order |\n\n### Priority Ordering\n\nBy default, returns the first error key in object order. With priority, returns the first matching priority key:\n\n```html file=\"./demo/snippets.html\"#L18-L22\n```\n\n**How it works:**\n1. Iterates through priority array\n2. Returns first key that exists in errors\n3. Falls back to first available key if no matches\n\n### Examples\n\n#### Basic Usage\n\n```html file=\"./demo/snippets.html\"#L2-L7\n```\n\n\n\n#### With Error Messages\n\n```html file=\"./demo/snippets.html\"#L10-L13\n```\n\n\n\n### Behavior\n\n- Returns empty string `''` if no errors\n- Pure pipe - re-runs when errors object reference changes\n- Always use `control.errors` (not `control`) for reactive updates"
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
"name": "Highlight Search",
|
|
577
|
+
"category": "pipes",
|
|
578
|
+
"categoryTitle": "Pipes",
|
|
579
|
+
"dirName": "highlight-search",
|
|
580
|
+
"routePath": "highlight-search",
|
|
581
|
+
"importPath": "ngx-oneforall/pipes/highlight-search",
|
|
582
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/highlight-search",
|
|
583
|
+
"description": "The HighlightSearchPipe highlights search matches by wrapping them in customizable HTML tags. Supports optional CSS classes for styling.",
|
|
584
|
+
"fullContent": "The `HighlightSearchPipe` highlights search matches by wrapping them in customizable HTML tags. Supports optional CSS classes for styling.\n\n### Installation\n\n```ts\nimport { HighlightSearchPipe } from 'ngx-oneforall/pipes/highlight-search';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L2\n```\n\n> **Note** Use `[innerHTML]` binding since this pipe returns HTML.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `value` | `string \\| null` | — | The text to search within |\n| `search` | `string \\| null` | — | The term to highlight |\n| `tag` | `string` | `'mark'` | HTML tag to wrap matches |\n| `cssClass` | `string` | — | Optional CSS class for wrapper |\n\n### Examples\n\n#### Basic Usage\n\n```html file=\"./snippets.html\"#L2-L3\n```\n\n#### Custom Tag\n\n```html file=\"./snippets.html\"#L6-L7\n```\n\n#### Custom CSS Class\n\n```html file=\"./snippets.html\"#L10-L14\n```\n\n#### Special Characters\n\nThe pipe escapes regex characters automatically:\n\n```html file=\"./snippets.html\"#L17-L18\n```\n\n### Behavior\n\n- **Case insensitive** - Matches 'angular' in 'Angular'\n- **Regex safe** - Escapes special characters (`$`, `+`, `?`, etc.)\n- **Null safe** - Returns original value or empty string for null inputs\n\n---\n\n#### Live Demo"
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
"name": "Initials",
|
|
588
|
+
"category": "pipes",
|
|
589
|
+
"categoryTitle": "Pipes",
|
|
590
|
+
"dirName": "initials",
|
|
591
|
+
"routePath": "initials",
|
|
592
|
+
"importPath": "ngx-oneforall/pipes/initials",
|
|
593
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/initials",
|
|
594
|
+
"description": "The initials pipe transforms a name or string into its initials. It handles single or multiple words and allows customizing the number of initials returned.",
|
|
595
|
+
"fullContent": "The `initials` pipe transforms a name or string into its initials. It handles single or multiple words and allows customizing the number of initials returned.\n\n### Installation\n\n```ts\nimport { InitialsPipe } from 'ngx-oneforall/pipes/initials';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L3\n```\n\n### Examples\n\n#### Basic Usage\n\n```html file=\"./snippets.html\"#L2-L3\n```\n\n#### Single Name\n\n```html file=\"./snippets.html\"#L6-L7\n```\n\n#### Custom Limit (1 Initial)\n\n```html file=\"./snippets.html\"#L10-L11\n```\n\n#### Custom Limit (3 Initials)\n\n```html file=\"./snippets.html\"#L14-L15\n```\n\n### Parameters\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `value` | `string` | - | The input string to transform |\n| `count` | `number` | `2` | The maximum number of initials to return |\n\n### Live Demo"
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
"name": "Pluralize Pipe",
|
|
599
|
+
"category": "pipes",
|
|
600
|
+
"categoryTitle": "Pipes",
|
|
601
|
+
"dirName": "pluralize",
|
|
602
|
+
"routePath": "pluralize",
|
|
603
|
+
"importPath": "ngx-oneforall/pipes/pluralize",
|
|
604
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/pluralize",
|
|
605
|
+
"description": "The PluralizePipe handles word pluralization with automatic English rules and custom plural support.",
|
|
606
|
+
"fullContent": "The `PluralizePipe` handles word pluralization with automatic English rules and custom plural support.\n\n### Installation\n\n```ts\nimport { PluralizePipe } from 'ngx-oneforall/pipes/pluralize';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L5\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `value` | `number \\| string` | — | The count to base pluralization on |\n| `singular` | `string` | — | The singular form of the word |\n| `plural` | `string \\| null` | auto | Custom plural form (auto-generated if not provided) |\n| `includeNumber` | `boolean` | `true` | Whether to prefix with the count |\n\n### Auto-Pluralization Rules\n\nWhen no custom plural is provided:\n- Ends with `s`, `x`, `z`, `ch`, `sh` → adds `es` (box → boxes)\n- Ends with consonant + `y` → changes to `ies` (city → cities)\n- Otherwise → adds `s` (apple → apples)\n\n### Examples\n\n#### Custom Plural Form\n\n```html file=\"./snippets.html\"#L8-L9\n```\n\n#### Without Number\n\n```html file=\"./snippets.html\"#L12-L13\n```\n\n### Behavior\n\n- Count `1` → singular form\n- Count `0`, `2+`, decimals, negatives → plural form\n- Throws error if singular form is empty\n\n---\n\n#### Live Demo"
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"name": "Range Pipe",
|
|
610
|
+
"category": "pipes",
|
|
611
|
+
"categoryTitle": "Pipes",
|
|
612
|
+
"dirName": "range",
|
|
613
|
+
"routePath": "range",
|
|
614
|
+
"importPath": "ngx-oneforall/pipes/range",
|
|
615
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/range",
|
|
616
|
+
"description": "The RangePipe generates an array of numbers in a range. Follows Python's range() convention.",
|
|
617
|
+
"fullContent": "The `RangePipe` generates an array of numbers in a range. Follows Python's `range()` convention.\n\n### Installation\n\n```ts\nimport { RangePipe } from 'ngx-oneforall/pipes/range';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L5\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `start` | `number` | — | Start value (or end if `end` not provided) |\n| `end` | `number` | — | End value (exclusive) |\n| `step` | `number` | `1` | Step increment (direction auto-detected) |\n\n### Examples\n\n#### Start and End\n\n```html file=\"./snippets.html\"#L8-L11\n```\n\n#### With Step\n\n```html file=\"./snippets.html\"#L14-L17\n```\n\n#### Decreasing Range\n\n```html file=\"./snippets.html\"#L20-L23\n```\n\n### Behavior\n\n| Input | Output |\n|-------|--------|\n| `5 \\| range` | `[0, 1, 2, 3, 4]` |\n| `1 \\| range:5` | `[1, 2, 3, 4]` |\n| `0 \\| range:10:2` | `[0, 2, 4, 6, 8]` |\n| `5 \\| range:1` | `[5, 4, 3, 2]` |\n\n- Step is normalized to positive (`Math.abs(step)`)\n- Zero step defaults to 1 to prevent infinite loops\n- Direction determined by comparing start and end\n\n---\n\n#### Live Demo"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"name": "Safe Html Pipe",
|
|
621
|
+
"category": "pipes",
|
|
622
|
+
"categoryTitle": "Pipes",
|
|
623
|
+
"dirName": "safe-html",
|
|
624
|
+
"routePath": "safe-html",
|
|
625
|
+
"importPath": "ngx-oneforall/pipes/safe-html",
|
|
626
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/safe-html",
|
|
627
|
+
"description": "The SafeHtmlPipe bypasses Angular's HTML sanitization to render trusted HTML content.",
|
|
628
|
+
"fullContent": "The `SafeHtmlPipe` bypasses Angular's HTML sanitization to render trusted HTML content.\n\n> **⚠️ Security Warning** Only use with trusted content. User input must be sanitized server-side.\n\n### Installation\n\n```ts\nimport { SafeHtmlPipe } from 'ngx-oneforall/pipes/safe-html';\n```\n\n### Usage\n\n```html\n<div [innerHTML]=\"htmlContent | safeHtml\"></div>\n```\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `value` | `string \\| null` | The HTML string to trust |\n\n### When to Use\n\n- **CMS content** - Admin-generated HTML from a trusted CMS\n- **Markdown output** - Pre-rendered markdown that's already sanitized\n- **Static HTML** - Hardcoded HTML strings in your codebase\n\n### When NOT to Use\n\n- **User input** - Never use with unsanitized user-provided content\n- **External APIs** - Content from untrusted third-party sources\n- **Query parameters** - URL parameters or form inputs\n\n### Behavior\n\n- Returns `SafeHtml` for valid strings\n- Returns empty `SafeHtml` for `null`/`undefined`\n- Throws error for non-string values\n\n### How it Works\n\nUses Angular's `DomSanitizer.bypassSecurityTrustHtml()` to mark content as trusted. This bypasses XSS protection, so ensure content is safe before use.\n\n---\n\n#### Live Demo"
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
"name": "Time Ago Pipe",
|
|
632
|
+
"category": "pipes",
|
|
633
|
+
"categoryTitle": "Pipes",
|
|
634
|
+
"dirName": "time-ago",
|
|
635
|
+
"routePath": "time-ago",
|
|
636
|
+
"importPath": "ngx-oneforall/pipes/time-ago",
|
|
637
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/time-ago",
|
|
638
|
+
"description": "The TimeAgoPipe displays relative time (e.g., \"2 hours ago\", \"in 3 days\"). Supports live updates, future dates, and customizable labels.",
|
|
639
|
+
"fullContent": "The `TimeAgoPipe` displays relative time (e.g., \"2 hours ago\", \"in 3 days\"). Supports live updates, future dates, and customizable labels.\n\n### Installation\n\n```ts\nimport { TimeAgoPipe } from 'ngx-oneforall/pipes/time-ago';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L2\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `value` | `string \\| Date` | — | Date to calculate time from |\n| `live` | `boolean` | `true` | Enable automatic updates |\n\n### Features\n\n| Output | Description |\n|--------|-------------|\n| `just now` | Within 10 seconds |\n| `X seconds ago` | Within 1 minute |\n| `X minutes ago` | Within 1 hour |\n| `X hours ago` | Within 1 day |\n| `X days ago` | Within 1 week |\n| `X weeks ago` | Within 1 month |\n| `X months ago` | Within 1 year |\n| `X years ago` | Over 1 year |\n| `in X seconds` | Future within 1 minute |\n| `in X days` | Future date |\n\n### Examples\n\n#### Basic Usage\n\n\n\n#### Disable Live Updates\n\n```html file=\"./snippets.html\"#L5-L5\n```\n\n#### Future Dates\n\n```html file=\"./snippets.html\"#L8-L9\n```\n\n### Custom Labels\n\nUse `provideTimeAgoPipeLabels` to customize:\n\n```typescript\nproviders: [\n provideTimeAgoPipeLabels(() => ({\n prefix: '',\n suffix: 'ago',\n futurePrefix: 'in',\n futureSuffix: '',\n justNow: 'just now',\n second: 'sec',\n seconds: 'secs',\n // ... other labels\n })),\n]\n```\n\n\n\n### Custom Clock\n\nControl update frequency:\n\n```typescript\nproviders: [\n provideTimeAgoPipeClock(() => timer(5000)), // Update every 5 seconds\n]\n```"
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
"name": "Truncate Pipe",
|
|
643
|
+
"category": "pipes",
|
|
644
|
+
"categoryTitle": "Pipes",
|
|
645
|
+
"dirName": "truncate",
|
|
646
|
+
"routePath": "truncate",
|
|
647
|
+
"importPath": "ngx-oneforall/pipes/truncate",
|
|
648
|
+
"url": "https://love1024.github.io/ngx-oneforall/pipes/truncate",
|
|
649
|
+
"description": "The TruncatePipe shortens strings to a specified length with optional word boundary and position support.",
|
|
650
|
+
"fullContent": "The `TruncatePipe` shortens strings to a specified length with optional word boundary and position support.\n\n### Installation\n\n```ts\nimport { TruncatePipe } from 'ngx-oneforall/pipes/truncate';\n```\n\n### Usage\n\n```html file=\"./snippets.html\"#L2-L2\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `value` | `string \\| null` | — | The string to truncate |\n| `limit` | `number` | `100` | Maximum character length |\n| `completeWords` | `boolean` | `false` | Truncate at word boundary (end only) |\n| `ellipsis` | `string` | `'…'` | String to append/insert when truncated |\n| `position` | `'start' \\| 'middle' \\| 'end'` | `'end'` | Where to truncate |\n\n### Examples\n\n#### End Truncation (default)\n\n```html file=\"./snippets.html\"#L5-L6\n```\n\n#### Start Truncation\n\n```html file=\"./snippets.html\"#L9-L10\n```\n\n#### Middle Truncation\n\n```html file=\"./snippets.html\"#L13-L14\n```\n\n#### Complete Words\n\n```html file=\"./snippets.html\"#L17-L18\n```\n\n### Behavior\n\n| Position | Example (limit: 8) | Output |\n|----------|-------------------|--------|\n| `end` | `Hello World` | `Hello Wo…` |\n| `start` | `Hello World` | `…lo World` |\n| `middle` | `Hello World` | `Hell…rld` |\n\n- `completeWords` only applies to end truncation\n- Returns empty string for `null`/`undefined` or `limit <= 0`\n\n---\n\n#### Live Demo"
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
"name": "Backoff Retry",
|
|
654
|
+
"category": "rxjs",
|
|
655
|
+
"categoryTitle": "RxJS",
|
|
656
|
+
"dirName": "backoff-retry",
|
|
657
|
+
"routePath": "backoff-retry",
|
|
658
|
+
"importPath": "ngx-oneforall/rxjs/backoff-retry",
|
|
659
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/backoff-retry",
|
|
660
|
+
"description": "The backOffRetry RxJS operator automatically retries failed observables with an exponential backoff strategy. It is essential for handling transient failures in network requests or unstable services.",
|
|
661
|
+
"fullContent": "The `backOffRetry` RxJS operator automatically retries failed observables with an exponential backoff strategy. It is essential for handling transient failures in network requests or unstable services.\n\n## Features\n\n- **Exponential Backoff** — Increases delay between retries exponentially\n- **Customizable Strategy** — Configure max retries, initial delay, and multiplier base\n- **Typed Configuration** — Full TypeScript support for configuration\n- **Seamless Integration** — Works with any RxJS observable\n\n## Installation\n\n```typescript\nimport { backOffRetry } from 'ngx-oneforall/rxjs/backoff-retry';\n```\n\n## Quick Start\n\n```typescript\nthis.http.get('/api/data').pipe(\n backOffRetry()\n).subscribe();\n```\n\n## Configuration\n\nThe operator accepts an optional `BackoffRetryConfig` object:\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `count` | `number` | `3` | Maximum number of retry attempts |\n| `delay` | `number` | `1000` | Initial delay in milliseconds |\n| `base` | `number` | `2` | Base for exponential calculation |\n| `maxDelay` | `number` | - | Optional cap for maximum delay (in ms) |\n\n### Custom Configuration\n\n```typescript\nthis.http.get('/api/unstable').pipe(\n backOffRetry({\n count: 5, // Retry 5 times\n delay: 500, // Start with 500ms delay\n base: 1.5 // Increase delay by 1.5x each time\n })\n).subscribe();\n```\n\n### With Max Delay Cap\n\nPrevent delays from growing too large:\n\n```typescript\nthis.http.get('/api/data').pipe(\n backOffRetry({\n count: 10, // Many retries\n delay: 1000, // Start at 1 second\n base: 2, // Double each time\n maxDelay: 30000 // But never wait more than 30 seconds\n })\n).subscribe();\n// Delays: 1s, 2s, 4s, 8s, 16s, 30s, 30s, 30s, 30s, 30s\n```\n\n## How It Works\n\nThe delay for each retry is calculated using the formula:\n\n`min(delay * Math.pow(base, retryCount - 1), maxDelay)`\n\nFor default values (`delay=1000`, `base=2`):\n- **Retry 1**: 1000ms\n- **Retry 2**: 2000ms\n- **Retry 3**: 4000ms\n\n## Examples\n\n### Robust API Calls\n\nWrap your HTTP requests to automatically recover from temporary network glitches:\n\n```typescript\nimport { catchError } from 'rxjs/operators';\nimport { of } from 'rxjs';\n\nthis.http.get('/api/users').pipe(\n backOffRetry(),\n catchError(err => {\n console.error('All retries failed', err);\n return of([]); // Fallback value\n })\n).subscribe();\n```\n\n### With Other Operators\n\nCombine with other operators for advanced flows:\n\n```typescript\nthis.source$.pipe(\n // Custom logic before retry\n tap({ error: () => console.log('Retrying...') }),\n backOffRetry({ count: 2 }),\n // Logic after all retries fail\n catchError(err => throwError(() => new Error('Service Unavailable')))\n);\n```\n\n## Demo\n\nSee the operator in action with visualized retry attempts:"
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
"name": "Catch Error With Fallback",
|
|
665
|
+
"category": "rxjs",
|
|
666
|
+
"categoryTitle": "RxJS",
|
|
667
|
+
"dirName": "catch-error-with-fallback",
|
|
668
|
+
"routePath": "catch-error-with-fallback",
|
|
669
|
+
"importPath": "ngx-oneforall/rxjs/catch-error-with-fallback",
|
|
670
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/catch-error-with-fallback",
|
|
671
|
+
"description": "The catchErrorWithFallback operator provides a clean, flexible way to handle errors in RxJS streams by automatically switching to a fallback value, observable, or dynamically generated result when an error occurs.",
|
|
672
|
+
"fullContent": "The `catchErrorWithFallback` operator provides a clean, flexible way to handle errors in RxJS streams by automatically switching to a fallback value, observable, or dynamically generated result when an error occurs.\n\n## Why Use catchErrorWithFallback?\n\nError handling is essential for robust applications, but RxJS's native `catchError` requires manually wrapping fallback values in `of()` observables. This operator simplifies the pattern:\n\n- **Cleaner Code**: No need to wrap static values in `of()`\n- **Flexible Fallbacks**: Support for static values, observables, or factory functions\n- **Error Callbacks**: Optional `onError` hook for logging or side effects\n- **Type Safety**: Full TypeScript support with proper type inference\n- **Dynamic Responses**: Factory functions can use the error to determine the fallback\n\n## How to Use\n\nImport the operator from `ngx-oneforall/rxjs`:\n\n```typescript\nimport { catchErrorWithFallback } from 'ngx-oneforall/rxjs/catch-error-with-fallback';\n```\n\n### Basic Usage with Static Fallback\n\n```typescript\nthis.http.get<User>('/api/user').pipe(\n catchErrorWithFallback({ id: 0, name: 'Guest' })\n).subscribe(user => {\n console.log(user); // Either API data or fallback guest user\n});\n```\n\n### Using an Observable Fallback\n\n```typescript\nthis.http.get<Post[]>('/api/posts').pipe(\n catchErrorWithFallback(this.getCachedPosts())\n).subscribe(posts => {\n // Falls back to cached posts on error\n});\n```\n\n### Dynamic Fallback with Factory Function\n\n```typescript\nthis.http.delete(`/api/items/${id}`).pipe(\n catchErrorWithFallback((error) => {\n if (error.status === 404) {\n return { success: true, message: 'Already deleted' };\n }\n return { success: false, message: 'Delete failed' };\n })\n).subscribe(result => {\n console.log(result.message);\n});\n```\n\n### With Error Logging\n\n```typescript\nthis.http.get<Data>('/api/data').pipe(\n catchErrorWithFallback([], {\n onError: (err) => console.error('API failed:', err)\n })\n).subscribe(data => {\n // Empty array as fallback, error logged\n});\n```\n\n## API\n\n### Signature\n\n```typescript\nfunction catchErrorWithFallback<T>(\n fallback: FallbackFactory<T>,\n options?: CatchErrorWithFallbackOptions\n): OperatorFunction<T, T>\n```\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `fallback` | `FallbackFactory<T>` | Static value, observable, or factory function |\n| `options` | `CatchErrorWithFallbackOptions` | Optional configuration |\n\n### FallbackFactory Type\n\n```typescript\ntype FallbackFactory<T> =\n | T // Static value\n | Observable<T> // Observable\n | ((error: unknown) => T | Observable<T>); // Factory function\n```\n\n### Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `onError` | `(error: unknown) => void` | Callback invoked when an error is caught |\n\n## Behavior\n\nThe operator follows these rules:\n\n1. **Pass-Through**: If no error occurs, values pass through unchanged\n2. **Static Fallback**: Plain values are automatically wrapped in `of()`\n3. **Observable Fallback**: Observables are subscribed to directly\n4. **Factory Functions**: Executed with the error, return value wrapped if needed\n5. **Error Callback**: `onError` is called before the fallback is applied\n\n## Use Cases\n\n### API with Fallback Data\n\n```typescript\nclass ProductService {\n getProducts(): Observable<Product[]> {\n return this.http.get<Product[]>('/api/products').pipe(\n catchErrorWithFallback(this.getDefaultProducts())\n );\n }\n\n private getDefaultProducts(): Product[] {\n return [\n { id: 1, name: 'Sample Product', price: 0 }\n ];\n }\n}\n```\n\n### Graceful Degradation\n\n```typescript\nthis.configService.getRemoteConfig().pipe(\n catchErrorWithFallback({\n theme: 'light',\n language: 'en',\n features: []\n }, {\n onError: (err) => this.logger.warn('Using default config', err)\n })\n).subscribe(config => {\n this.applyConfig(config);\n});\n```\n\n### Error-Specific Handling\n\n```typescript\nthis.http.post('/api/payment', paymentData).pipe(\n catchErrorWithFallback((error: any) => {\n if (error.status === 429) {\n return of({ retryAfter: error.headers.get('Retry-After') });\n }\n if (error.status >= 500) {\n return of({ serverError: true });\n }\n return throwError(() => error); // Re-throw client errors\n })\n)\n```\n\n### Logging and Metrics\n\n```typescript\nthis.dataService.fetchCriticalData().pipe(\n catchErrorWithFallback(this.getCachedData(), {\n onError: (err) => {\n this.analytics.trackError('critical_data_fetch_failed', err);\n this.notifySupport(err);\n }\n })\n)\n```\n\n### Form Submission with Retry\n\n```typescript\nsubmitForm(data: FormData): Observable<SubmitResult> {\n return this.http.post<SubmitResult>('/api/submit', data).pipe(\n catchErrorWithFallback((error: any) => {\n // Return observable for async retry logic\n return of(null).pipe(\n delay(2000),\n switchMap(() => this.http.post<SubmitResult>('/api/submit', data))\n );\n }, {\n onError: (err) => console.warn('First attempt failed, retrying...')\n })\n );\n}\n```\n\n## Comparison with Native catchError\n\n### Native RxJS\n\n```typescript\n// Verbose - must wrap in of()\nsource$.pipe(\n catchError(error => {\n console.error(error);\n return of(defaultValue);\n })\n)\n```\n\n### With catchErrorWithFallback\n\n```typescript\n// Concise - automatic wrapping\nsource$.pipe(\n catchErrorWithFallback(defaultValue, {\n onError: error => console.error(error)\n })\n)\n```\n\n## Demo\n\nExplore the operator with an interactive demonstration:"
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"name": "Data Polling",
|
|
676
|
+
"category": "rxjs",
|
|
677
|
+
"categoryTitle": "RxJS",
|
|
678
|
+
"dirName": "data-polling",
|
|
679
|
+
"routePath": "data-polling",
|
|
680
|
+
"importPath": "ngx-oneforall/rxjs/data-polling",
|
|
681
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/data-polling",
|
|
682
|
+
"description": "It uses timer and switchMap to repeatedly call a loader function, making it perfect for real-time data updates.",
|
|
683
|
+
"fullContent": "`dataPolling` is an RxJS operator that automatically polls a data source at specified intervals.\n\nIt uses `timer` and `switchMap` to repeatedly call a loader function, making it perfect for real-time data updates.\n\n## Usage\n\n{{ NgDocActions.demo(\"DataPollingDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { Subject } from 'rxjs';\nimport { dataPolling } from 'ngx-oneforall/rxjs/data-polling';\n\nconst trigger = new Subject<void>();\n\ntrigger.pipe(\n dataPolling({\n loader: () => fetchData(), // Your data fetching function\n interval: 5000 // Poll every 5 seconds\n })\n).subscribe(data => {\n console.log('Received data:', data);\n});\n\n// Start polling\ntrigger.next();\n```\n\n### With HTTP Requests\n\n```typescript\nimport { HttpClient } from '@angular/common/http';\nimport { Subject } from 'rxjs';\nimport { dataPolling } from 'ngx-oneforall/rxjs/data-polling';\n\nexport class MyComponent {\n constructor(private http: HttpClient) {}\n\n startPolling() {\n const trigger = new Subject<void>();\n \n trigger.pipe(\n dataPolling({\n loader: () => this.http.get('/api/status'),\n interval: 10000 // Poll every 10 seconds\n })\n ).subscribe(status => {\n console.log('Server status:', status);\n });\n\n trigger.next();\n }\n}\n```\n\n## API\n\n`dataPolling<T>(config: DataPollingConfig<T>): OperatorFunction<unknown, T>`\n\n### Configuration\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `loader` | `() => Observable<T>` | - | Function that returns an Observable of the data to poll |\n| `interval` | `number` | - | Polling interval in milliseconds |\n| `retryCount` | `number` | `0` | Number of retry attempts on error |\n| `retryDelay` | `number` | `1000` | Delay between retries in milliseconds |\n\n### Behavior\n\n- Immediately calls the loader when the source emits\n- Continues polling at the specified interval\n- Cancels previous polling if the source emits again\n- Retries failed requests up to `retryCount` times with `retryDelay` between attempts\n\n### Example with Retry\n\n```typescript\ntrigger.pipe(\n dataPolling({\n loader: () => this.http.get('/api/data'),\n interval: 5000,\n retryCount: 3, // Retry up to 3 times\n retryDelay: 1000 // Wait 1 second between retries\n })\n).subscribe(data => console.log(data));\n```"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"name": "Debug",
|
|
687
|
+
"category": "rxjs",
|
|
688
|
+
"categoryTitle": "RxJS",
|
|
689
|
+
"dirName": "debug",
|
|
690
|
+
"routePath": "debug",
|
|
691
|
+
"importPath": "ngx-oneforall/rxjs/debug",
|
|
692
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/debug",
|
|
693
|
+
"description": "The operator uses different console methods and colors to help you distinguish between event types:",
|
|
694
|
+
"fullContent": "`debug` is a utility operator that provides styled logging for RxJS streams. It wraps the `tap` operator to log `next`, `error`, and `complete` events with a custom tag and distinct CSS styles, making it easier to debug complex observable chains in the browser console.\n\n## Usage\n\n{{ NgDocActions.demo(\"DebugDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { of } from 'rxjs';\nimport { debug } from 'ngx-oneforall/rxjs/debug';\n\nconst source$ = of(1, 2, 3).pipe(\n debug('NumbersStream')\n);\n\nsource$.subscribe();\n// Console output:\n// [NumbersStream: Next] 1\n// [NumbersStream: Next] 2\n// [NumbersStream: Next] 3\n// [NumbersStream]: Complete\n```\n\n## API\n\n`debug<T>(tag: string, when?: (value?: T) => boolean): MonoTypeOperatorFunction<T>`\n\n### Parameters\n\n- **tag**: A string label that identifies the stream in the console output.\n- **when**: (Optional) A function that returns a boolean. Logging only occurs if this function returns `true`. It receives the emitted value as an argument (for `next` events).\n\n### Examples\n\n#### Conditional Logging\n\n```typescript\nimport { of } from 'rxjs';\nimport { debug } from 'ngx-oneforall/rxjs/debug';\n\nconst isDev = true;\nconst source$ = of('data').pipe(\n debug('MyStream', () => isDev)\n);\n```\n\n#### Filtering Logs by Value\n\n```typescript\nconst source$ = of(1, 10, 100).pipe(\n debug('BigNumbers', (val) => val >= 10)\n);\n// Only 10 and 100 will be logged.\n```\n\n### Console Styles\n\nThe operator uses different console methods and colors to help you distinguish between event types:\n\n\n- **Next**: `console.log` - Cyan background with white text.\n- **Error**: `console.error` - Pinkish-red background with white text.\n- **Complete**: `console.info` - Teal background with white text.\n\n### Benefits\n\n- **Visibility**: Easily spot your stream logs among other console output.\n- **No Boilerplate**: Replaces multiple `tap(val => console.log(val))` calls with a single operator.\n- **State Tracking**: Automatically handles error and completion logging without extra code."
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
"name": "Live Search",
|
|
698
|
+
"category": "rxjs",
|
|
699
|
+
"categoryTitle": "RxJS",
|
|
700
|
+
"dirName": "live-search",
|
|
701
|
+
"routePath": "live-search",
|
|
702
|
+
"importPath": "ngx-oneforall/rxjs/live-search",
|
|
703
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/live-search",
|
|
704
|
+
"description": "It combines debounceTime, distinctUntilChanged, and switchMap to provide an optimal search experience.",
|
|
705
|
+
"fullContent": "`liveSearch` is an RxJS operator for implementing live search functionality with automatic debouncing, duplicate filtering, and request cancellation.\n\nIt combines `debounceTime`, `distinctUntilChanged`, and `switchMap` to provide an optimal search experience.\n\n## Usage\n\n{{ NgDocActions.demo(\"LiveSearchDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { liveSearch } from 'ngx-oneforall/rxjs/live-search';\n\nexport class SearchComponent {\n searchControl = new FormControl('', { nonNullable: true });\n\n ngOnInit() {\n this.searchControl.valueChanges.pipe(\n liveSearch(300, (query) => this.searchAPI(query))\n ).subscribe(results => {\n console.log('Search results:', results);\n });\n }\n\n private searchAPI(query: string) {\n return this.http.get(`/api/search?q=${query}`);\n }\n}\n```\n\n### With HttpClient\n\n```typescript\nimport { HttpClient } from '@angular/common/http';\nimport { FormControl } from '@angular/forms';\nimport { liveSearch } from 'ngx-oneforall/rxjs/live-search';\n\nexport class ProductSearchComponent {\n searchControl = new FormControl('');\n results$ = this.searchControl.valueChanges.pipe(\n liveSearch(500, (query) => this.searchProducts(query))\n );\n\n constructor(private http: HttpClient) {}\n\n private searchProducts(query: string) {\n return this.http.get<Product[]>(`/api/products/search`, {\n params: { q: query }\n });\n }\n}\n```\n\n## API\n\n`liveSearch<T>(delay: number, dataProducer: (query: string) => Observable<T>)`\n\n### Parameters\n\n- **delay**: Debounce delay in milliseconds\n- **dataProducer**: A function that takes the query string and returns an Observable of search results\n\n### Behavior\n\n- Debounces input to reduce API calls\n- Filters out consecutive duplicate values\n- Automatically cancels previous search requests when a new one is initiated\n- The delay is specified in **milliseconds**\n\n### Benefits\n\n- Reduces server load by debouncing rapid input changes\n- Prevents duplicate searches\n- Always shows the most recent search results\n- Handles race conditions automatically"
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"name": "Loading Status",
|
|
709
|
+
"category": "rxjs",
|
|
710
|
+
"categoryTitle": "RxJS",
|
|
711
|
+
"dirName": "loading-status",
|
|
712
|
+
"routePath": "loading-status",
|
|
713
|
+
"importPath": "ngx-oneforall/rxjs/loading-status",
|
|
714
|
+
"url": "https://love1024.github.io/ngx-oneforall/rxjs/loading-status",
|
|
715
|
+
"description": "In your component, you can then easily handle the different states:",
|
|
716
|
+
"fullContent": "`loadingStatus` is an RxJS operator that simplifies tracking the state of an asynchronous operation (like an API call). It automatically catches errors and provides a unified `ResourceResult<T>` object containing the loading status, the data, and any potential error.\n\n## Usage\n\n{{ NgDocActions.demo(\"LoadingStatusDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n\nIn your component, you can then easily handle the different states:\n\n{% raw %}\n```html file=\"./snippet.html\"#L1-L13\n```\n{% endraw %}\n\n## API\n\n`loadingStatus<T>(): OperatorFunction<T, ResourceResult<T>>`\n\n### ResourceResult<T> Interface\n\n```typescript\ntype ResourceResult<T> = {\n isLoading: boolean;\n status: 'loading' | 'success' | 'error';\n data: T | null;\n error?: unknown;\n}\n```\n\n### Behavior\n\n- **Initial State**: Immediately emits `{ status: 'loading', data: null, isLoading: true }` upon subscription.\n- **Success State**: When the source observable emits data, it transforms it to `{ status: 'success', data: T, isLoading: false }`.\n- **Error State**: If the source observable errors, it catches it and emits `{ status: 'error', data: null, error: unknown, isLoading: false }`.\n\n### Benefits\n\n- **Unified State**: No need to manage separate `isLoading`, `error`, and `data` variables or signals.\n- **Error Handling**: Automatically catches errors so the stream doesn't terminate unexpectedly (it transforms the error into a value).\n- **Type Safety**: Provides a strongly typed result object."
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
"name": "Cache",
|
|
720
|
+
"category": "services",
|
|
721
|
+
"categoryTitle": "Services",
|
|
722
|
+
"dirName": "cache",
|
|
723
|
+
"routePath": "cache",
|
|
724
|
+
"importPath": "ngx-oneforall/services/cache",
|
|
725
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/cache",
|
|
726
|
+
"description": "Advanced caching service with TTL, versioning, and multi-storage support.",
|
|
727
|
+
"fullContent": "Advanced caching service with TTL, versioning, and multi-storage support.\n\n## Features\n\n- **Multi-Storage** — Support for `memory`, `local`, and `session` storage\n- **Time-to-Live (TTL)** — Auto-expiration for cached entries\n- **Versioning** — Invalidate entire cache when version changes\n- **SSR Safe** — Graceful fallback to memory on server\n- **Type-Safe** — Generic support for stored values\n\n---\n\n## Installation\n\n```typescript\nimport { \n CacheService, \n provideCacheService,\n CacheOptions \n} from 'ngx-oneforall/services/cache';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { CacheService, provideCacheService } from 'ngx-oneforall/services/cache';\n\n@Component({\n selector: 'app-demo',\n template: `<p>User: user() }}</p>`,\n providers: [\n provideCacheService({\n storage: 'local',\n ttl: 3600 * 1000, // 1 hour\n version: 'v1.0.0'\n })\n ]\n})\nexport class DemoComponent {\n private cache = inject(CacheService);\n\n user = linkedSignal(() => {\n // Check cache first\n const cached = this.cache.get<User>('current_user');\n if (cached) return cached;\n \n // Fetch if missing\n return this.fetchUser();\n });\n\n saveUser(user: User) {\n this.cache.set('current_user', user);\n }\n}\n```\n\n---\n\n## API Reference\n\n### `get<T>(key, storage?)`\n\nRetrieve a value from cache. Returns `null` if missing or expired.\n\n```typescript\n// Get from default storage\nconst value = cache.get<string>('key');\n\n// Get from specific storage\nconst memoryValue = cache.get<number>('count', 'memory');\n```\n\n### `set<T>(key, value, config?)`\n\nStore a value with optional overrides.\n\n```typescript\n// Use global config\ncache.set('user', user);\n\n// Override TTL for this specific item (e.g. 5 seconds)\ncache.set('temp', data, { ttl: 5000 });\n```\n\n### `has(key, storage?)`\n\nCheck if a valid (non-expired) entry exists.\n\n```typescript\nif (cache.has('token')) {\n // ...\n}\n```\n\n### `remove(key, storage?)`\n\nRemove a specific entry.\n\n### `clear(storage?)`\n\nClear all entries managed by this service (respects prefix).\n\n---\n\n## Configuration Options\n\nPass these options to `provideCacheService()`:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `storage` | `'memory' \\| 'local' \\| 'session'` | `'memory'` | Default storage engine |\n| `ttl` | `number` | `3600000` (1h) | Global expiration time in ms |\n| `version` | `string` | `INTERNAL` | Cache version string |\n| `storagePrefix` | `string` | `undefined` | Key prefix in storage |\n\n---\n\n## Versioning & Invalidation\n\nWhen you deploy a new version of your app, you often want to invalidate old cache entries to prevent schema mismatches.\n\n```typescript\nprovideCacheService({\n version: 'v2.0.0', // Changing this invalidates all previous 'v1.0.0' entries\n})\n```\n\nWhen `CacheService` detects a version mismatch for a key, it automatically removes that entry and returns `null`.\n\n---\n\n## Live Demo"
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
"name": "Clipboard",
|
|
731
|
+
"category": "services",
|
|
732
|
+
"categoryTitle": "Services",
|
|
733
|
+
"dirName": "clipboard",
|
|
734
|
+
"routePath": "clipboard",
|
|
735
|
+
"importPath": "ngx-oneforall/services/clipboard",
|
|
736
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/clipboard",
|
|
737
|
+
"description": "A simple service for copying and reading text from the system clipboard with automatic fallback for older browsers.",
|
|
738
|
+
"fullContent": "A simple service for copying and reading text from the system clipboard with automatic fallback for older browsers.\n\n## Features\n\n- **Modern Clipboard API** — Uses `navigator.clipboard` when available\n- **Automatic Fallback** — Falls back to `execCommand('copy')` for older browsers\n- **SSR Safe** — Returns safe defaults on server\n- **Promise-based** — Async/await friendly API\n\n---\n\n## Installation\n\n```typescript\nimport { ClipboardService } from 'ngx-oneforall/services/clipboard';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { ClipboardService } from 'ngx-oneforall/services/clipboard';\n\n@Component({\n selector: 'app-demo',\n template: `\n <button (click)=\"copyText()\">Copy</button>\n <button (click)=\"pasteText()\">Paste</button>\n `,\n providers: [ClipboardService],\n})\nexport class DemoComponent {\n private clipboard = inject(ClipboardService);\n\n async copyText() {\n const success = await this.clipboard.copy('Hello World');\n console.log(success ? 'Copied!' : 'Failed to copy');\n }\n\n async pasteText() {\n const text = await this.clipboard.read();\n console.log('Clipboard:', text);\n }\n}\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `copy(text)` | `Promise<boolean>` | Copies text to clipboard, returns `true` on success |\n| `read()` | `Promise<string>` | Reads text from clipboard, returns `''` on failure |\n\n---\n\n## SSR Behavior\n\nOn server-side rendering (SSR):\n\n| Method | SSR Return |\n|--------|------------|\n| `copy()` | `false` |\n| `read()` | `''` |\n\n---\n\n## Browser Compatibility\n\n> [!NOTE]\n> The Clipboard API requires user interaction and HTTPS. On HTTP or without user gesture, the fallback mechanism will be used for `copy()`.\n\n---\n\n## Live Demo"
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
"name": "Cookie",
|
|
742
|
+
"category": "services",
|
|
743
|
+
"categoryTitle": "Services",
|
|
744
|
+
"dirName": "cookie",
|
|
745
|
+
"routePath": "cookie",
|
|
746
|
+
"importPath": "ngx-oneforall/services/cookie",
|
|
747
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/cookie",
|
|
748
|
+
"description": "A lightweight service for managing browser cookies with SSR safety and security-aware defaults.",
|
|
749
|
+
"fullContent": "A lightweight service for managing browser cookies with SSR safety and security-aware defaults.\n\n## Features\n\n- **CRUD Operations** — Get, set, delete individual or all cookies\n- **SSR Safe** — Returns safe defaults on server (no `document` access)\n- **Security Compliant** — Auto-enforces `secure` flag when `SameSite=None`\n- **Flexible Options** — Expiry, path, domain, partitioned, and more\n\n---\n\n## Installation\n\n```typescript\nimport { CookieService, provideCookieService } from 'ngx-oneforall/services/cookie';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { CookieService, provideCookieService } from 'ngx-oneforall/services/cookie';\n\n@Component({\n selector: 'app-demo',\n template: `<button (click)=\"save()\">Save</button>`,\n providers: [provideCookieService()],\n})\nexport class DemoComponent {\n private cookies = inject(CookieService);\n\n save() {\n // Set cookie with 1 hour expiry\n this.cookies.set('user', 'JohnDoe', { expires: 3600 });\n \n // Get cookie value\n const user = this.cookies.get('user'); // 'JohnDoe'\n \n // Delete cookie\n this.cookies.delete('user');\n }\n}\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `get(name)` | `string` | Returns cookie value or `''` if not found |\n| `getAll()` | `Record<string, string>` | Returns all cookies as key-value object |\n| `set(name, value, options?)` | `void` | Sets a cookie with optional config |\n| `delete(name, options?)` | `void` | Deletes the specified cookie |\n| `deleteAll(options?)` | `void` | Deletes all cookies |\n\n---\n\n## Cookie Options\n\n```typescript\ninterface CookieOptions {\n sameSite?: 'Strict' | 'Lax' | 'None'; // Default: 'Lax'\n domain?: string;\n path?: string;\n secure?: boolean;\n partitioned?: boolean;\n expires?: number | Date; // number = seconds\n}\n```\n\n---\n\n## SSR Behavior\n\nOn server-side rendering (SSR), all methods return safe defaults:\n\n| Method | SSR Return |\n|--------|------------|\n| `get()` | `''` |\n| `getAll()` | `{}` |\n| `set()` / `delete()` / `deleteAll()` | No-op |\n\n---\n\n## Security Notes\n\n> [!WARNING]\n> When `SameSite=None` is set, the service automatically enables `secure: true` and logs a console warning. This is required by browser security policies.\n\n---\n\n## Live Demo"
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
"name": "Device",
|
|
753
|
+
"category": "services",
|
|
754
|
+
"categoryTitle": "Services",
|
|
755
|
+
"dirName": "device",
|
|
756
|
+
"routePath": "device",
|
|
757
|
+
"importPath": "ngx-oneforall/services/device",
|
|
758
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/device",
|
|
759
|
+
"description": "Detect device type and orientation with automatic updates on resize and orientation changes.",
|
|
760
|
+
"fullContent": "Detect device type and orientation with automatic updates on resize and orientation changes.\n\n## Features\n\n- **Device Type Detection** — Detect `mobile`, `tablet`, or `desktop`\n- **Orientation Detection** — Detect `portrait` or `landscape`\n- **Reactive Signal** — Exposes `deviceInfoSignal` for template bindings\n- **SSR Safe** — No window subscriptions on server\n\n---\n\n## Installation\n\n```typescript\nimport { DeviceService, provideDeviceService } from 'ngx-oneforall/services/device';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { DeviceService, provideDeviceService } from 'ngx-oneforall/services/device';\n\n@Component({\n selector: 'app-demo',\n template: `\n @if (device.deviceInfoSignal(); as info) {\n <p>Type: </p>\n <p>Orientation: </p>\n }\n `,\n providers: [provideDeviceService()],\n})\nexport class DemoComponent {\n device = inject(DeviceService);\n}\n```\n\n---\n\n## API Reference\n\n### Properties\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `deviceInfo` | `DeviceInfo \\| null` | Current device info object |\n| `deviceType` | `DeviceType \\| null` | `'mobile'` \\| `'tablet'` \\| `'desktop'` |\n| `orientation` | `Orientation \\| null` | `'portrait'` \\| `'landscape'` |\n| `deviceInfoSignal` | `Signal<DeviceInfo \\| null>` | Reactive signal for templates |\n\n### Methods\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `isMobile()` | `boolean` | True if device is mobile |\n| `isTablet()` | `boolean` | True if device is tablet |\n| `isDesktop()` | `boolean` | True if device is desktop |\n| `isPortrait()` | `boolean` | True if orientation is portrait |\n| `isLandscape()` | `boolean` | True if orientation is landscape |\n\n---\n\n## Types\n\n```typescript\ninterface DeviceInfo {\n type: 'mobile' | 'tablet' | 'desktop';\n orientation: 'portrait' | 'landscape';\n}\n```\n\n---\n\n## Detection Strategy\n\n1. **userAgentData** — Most accurate (Chromium browsers)\n2. **iPadOS detection** — Handles iPadOS 13+ (reports as Macintosh)\n3. **User Agent regex** — Fallback pattern matching\n4. **Touch + screen size** — Final fallback for unknown devices\n\n---\n\n## SSR Behavior\n\nOn server-side rendering:\n- `deviceInfo`, `deviceType`, `orientation` return `null`\n- No window event subscriptions are created\n\n---\n\n## Live Demo"
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
"name": "Event",
|
|
764
|
+
"category": "services",
|
|
765
|
+
"categoryTitle": "Services",
|
|
766
|
+
"dirName": "event-service",
|
|
767
|
+
"routePath": "event-service",
|
|
768
|
+
"importPath": "ngx-oneforall/services/event-service",
|
|
769
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/event-service",
|
|
770
|
+
"description": "A lightweight pub-sub service for event-based communication between Angular components and services.",
|
|
771
|
+
"fullContent": "A lightweight pub-sub service for event-based communication between Angular components and services.\n\n## Features\n\n- **Dispatch Events** — Publish custom events with optional typed payloads\n- **Type-Safe Subscriptions** — Use generics for typed event data\n- **Decoupled Communication** — No direct component references needed\n- **SSR Safe** — Works in server-side rendering environments\n\n---\n\n## Installation\n\n```typescript\nimport { EventService, provideEventService, AppEvent } from 'ngx-oneforall/services/event';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { EventService, provideEventService } from 'ngx-oneforall/services/event';\n\n@Component({\n selector: 'app-demo',\n template: `\n <button (click)=\"sendEvent()\">Send Event</button>\n @if (lastEvent) {\n <p>Last: </p>\n }\n `,\n providers: [provideEventService()],\n})\nexport class DemoComponent {\n private events = inject(EventService);\n lastEvent?: { name: string; data?: unknown };\n\n constructor() {\n this.events.getEventEmitter()\n .pipe(takeUntilDestroyed())\n .subscribe(event => this.lastEvent = event);\n }\n\n sendEvent() {\n this.events.dispatchEvent('myEvent', { foo: 'bar' });\n }\n}\n```\n\n---\n\n## Type-Safe Events\n\nUse generics to get typed event data:\n\n```typescript\ninterface UserData {\n userId: string;\n name: string;\n}\n\n// Typed subscription\nthis.events.getEventEmitter<UserData>().subscribe(event => {\n console.log(event.data?.userId); // ✅ typed as string\n console.log(event.data?.name); // ✅ typed as string\n});\n\n// Dispatch with matching type\nthis.events.dispatchEvent('user:login', { userId: '123', name: 'John' });\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `dispatchEvent(name, data?)` | `void` | Dispatches an event with name and optional data |\n| `getEventEmitter<T>()` | `Observable<AppEvent<T>>` | Returns typed observable stream of events |\n\n---\n\n## Types\n\n```typescript\ninterface AppEvent<T = unknown> {\n name: string;\n data?: T;\n}\n```\n\n---\n\n## When to Use\n\n- Cross-component communication without parent-child relationship\n- Decoupling event producers from consumers\n- Broadcasting state changes to multiple subscribers\n\n---\n\n## Live Demo"
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
"name": "History",
|
|
775
|
+
"category": "services",
|
|
776
|
+
"categoryTitle": "Services",
|
|
777
|
+
"dirName": "history",
|
|
778
|
+
"routePath": "history",
|
|
779
|
+
"importPath": "ngx-oneforall/services/history",
|
|
780
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/history",
|
|
781
|
+
"description": "",
|
|
782
|
+
"fullContent": "`HistoryService` tracks navigation and provides back navigation with fallback support.\n\n## Features\n\n- **Navigation Tracking** — Tracks route changes after calling `startTracking()`\n- **Previous URL** — Access the previous page URL\n- **Back with Fallback** — Go back or navigate to fallback if no history\n- **Replace Navigation** — Navigate without adding to history\n- **SSR Safe** — Does nothing on server-side\n\n---\n\n## Installation\n\n```typescript\nimport { provideHistoryService, HistoryService } from 'ngx-oneforall/services/history';\n\n// app.config.ts\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideHistoryService({ maxSize: 100 }),\n ],\n};\n\n// app.component.ts - Start tracking\nconstructor() {\n inject(HistoryService).startTracking();\n}\n```\n\n---\n\n## API Reference\n\n### Configuration\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `maxSize` | `number` | `50` | Maximum history entries to keep |\n\n### Service Methods\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `startTracking()` | `void` | Start tracking navigation events |\n| `back()` | `void` | Navigate back if possible |\n| `backOrFallback(url)` | `void` | Go back or navigate to fallback URL |\n| `forward()` | `void` | Navigate forward |\n| `replaceCurrent(url)` | `Promise<boolean>` | Navigate without adding to history |\n| `clear()` | `void` | Clear history stack |\n| `getHistory()` | `string[]` | Get full history array |\n\n### Signals\n\n| Signal | Type | Description |\n|--------|------|-------------|\n| `currentUrl()` | `string \\| null` | Current URL |\n| `previousUrl()` | `string \\| null` | Previous URL |\n| `canGoBack()` | `boolean` | Whether back is possible |\n| `length()` | `number` | History stack size |\n\n---\n\n## Basic Usage\n\n```typescript\n@Component({...})\nexport class MyComponent {\n private history = inject(HistoryService);\n\n goBack() {\n this.history.backOrFallback('/home');\n }\n\n handleLoginSuccess() {\n // Replace login page in history\n this.history.replaceCurrent('/dashboard');\n }\n}\n```\n\n---\n\n## Live Demo"
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"name": "Idle",
|
|
786
|
+
"category": "services",
|
|
787
|
+
"categoryTitle": "Services",
|
|
788
|
+
"dirName": "idle",
|
|
789
|
+
"routePath": "idle",
|
|
790
|
+
"importPath": "ngx-oneforall/services/idle",
|
|
791
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/idle",
|
|
792
|
+
"description": "You can also provide it at the application level in app.config.ts:",
|
|
793
|
+
"fullContent": "`IdleService` detects user inactivity based on DOM events (mouse, keyboard, touch, scroll).\n\n## Features\n\n- **Signal & Observable API** — Exposes `isIdle` signal and `isIdle$` observable\n- **Configurable** — Customize timeout duration and monitored events\n- **SSR Safe** — No listeners attached on server\n- **Passive Events** — Uses passive event listeners for better performance\n- **Auto Cleanup** — Automatically stops on component/service destroy\n---\n\n## Usage\n\n```typescript\nimport { IdleService, provideIdleService } from 'ngx-oneforall/services/idle';\n\n@Component({\n providers: [provideIdleService({ timeout: 60000 })], // 1 minute\n})\nexport class AppComponent {\n private idle = inject(IdleService);\n\n constructor() {\n this.idle.start();\n\n effect(() => {\n if (this.idle.isIdle()) {\n console.log('User is idle!');\n }\n });\n }\n}\n```\n\nYou can also provide it at the application level in `app.config.ts`:\n\n```typescript\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideIdleService({ timeout: 300000 }), // 5 minutes\n ],\n};\n```\n\n---\n\n## Runtime Configuration\n\nUse `configure()` to override settings at runtime. If monitoring is already running, it will automatically restart with the new options:\n\n```typescript\n// Change timeout dynamically\nthis.idle.configure({ timeout: 120000 }); // 2 minutes\n\n// Change monitored events\nthis.idle.configure({ \n events: ['mousemove', 'keydown', 'click'] \n});\n\n// Change both\nthis.idle.configure({ \n timeout: 30000,\n events: ['mousemove', 'touchstart'] \n});\n```\n\n---\n\n## API\n\n### Methods\n\n| Method | Description |\n|--------|-------------|\n| `configure(options)` | Set timeout and events to monitor |\n| `start()` | Start monitoring for activity |\n| `stop()` | Stop monitoring |\n| `reset()` | Reset idle timer |\n\n### Properties\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `isIdle` | `Signal<boolean>` | Current idle state |\n| `isIdle$` | `Observable<boolean>` | Observable stream |\n\n### Monitored Events\n\nBy default, the service listens for the following DOM events to detect user activity:\n\n- `mousemove` - Mouse movement\n- `keydown` - Keyboard input\n- `touchstart` - Touch interactions\n- `scroll` - Page scrolling\n- `click` - Mouse clicks\n\nYou can customize these via the `events` option in `IdleOptions`.\n\n### IdleOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `timeout` | `number` | `300000` (5min) | Idle timeout in ms |\n| `events` | `string[]` | `['mousemove', 'keydown', 'touchstart', 'scroll', 'click']` | Events to monitor |\n\n## Demo\n\n{{ NgDocActions.demo(\"IdleDemoComponent\", { container: true }) }}"
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
"name": "Jwt",
|
|
797
|
+
"category": "services",
|
|
798
|
+
"categoryTitle": "Services",
|
|
799
|
+
"dirName": "jwt",
|
|
800
|
+
"routePath": "jwt",
|
|
801
|
+
"importPath": "ngx-oneforall/services/jwt",
|
|
802
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/jwt",
|
|
803
|
+
"description": "Decode, validate, and extract claims from JSON Web Tokens (JWTs) with a configurable token source.",
|
|
804
|
+
"fullContent": "Decode, validate, and extract claims from JSON Web Tokens (JWTs) with a configurable token source.\n\n## Features\n\n- **Decode JWT** — Extract header and payload without verification\n- **Claim Access** — Get individual claims with type safety\n- **Validity Checks** — Check expiration, not-yet-valid, and overall validity\n- **Configurable Token Source** — Provide custom `tokenGetter` function\n- **Error Handling** — Clear errors for missing, malformed, or invalid tokens\n\n---\n\n## Installation\n\n```typescript\nimport { JwtService, provideJwtService } from 'ngx-oneforall/services/jwt';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { JwtService, provideJwtService } from 'ngx-oneforall/services/jwt';\n\n@Component({\n selector: 'app-demo',\n template: `<p>Token valid: </p>`,\n providers: [\n provideJwtService({\n tokenGetter: () => localStorage.getItem('access_token') ?? '',\n }),\n ],\n})\nexport class DemoComponent {\n private jwt = inject(JwtService);\n isValid = this.jwt.isValid();\n}\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `decodeHeader<T>(token?)` | `T` | Decode and return JWT header |\n| `decodeBody<T>(token?)` | `T` | Decode and return JWT payload |\n| `getClaim<T>(claim, token?)` | `T \\| undefined` | Get specific claim value |\n| `getExpirationDate(token?)` | `Date \\| null` | Get `exp` claim as Date |\n| `getIssuedAtDate(token?)` | `Date \\| null` | Get `iat` claim as Date |\n| `isExpired(token?, offset?)` | `boolean` | Check if token is expired |\n| `isNotYetValid(token?)` | `boolean` | Check `nbf` claim |\n| `isValid(token?, offset?)` | `boolean` | Check structure + expiration + nbf |\n| `getTimeUntilExpiration(token?)` | `number \\| null` | Milliseconds until expiration |\n| `getToken()` | `string` | Get token from tokenGetter |\n| `getConfig()` | `JwtOptions` | Get service configuration |\n\n---\n\n## Configuration\n\n```typescript\ninterface JwtOptions {\n tokenGetter?: () => string | null;\n authScheme?: string; // Default: 'Bearer '\n headerName?: string; // Default: 'Authorization'\n errorOnNoToken?: boolean;\n skipAddingIfExpired?: boolean;\n allowedDomains?: (string | RegExp)[];\n skipUrls?: (string | RegExp)[];\n refreshTokenHandler?: RefreshTokenHandler;\n}\n```\n\n---\n\n## Auth Guard Example\n\n```typescript\nexport const authGuard: CanActivateFn = () => {\n const jwt = inject(JwtService);\n const router = inject(Router);\n\n if (jwt.isExpired()) {\n router.navigateByUrl('/login');\n return false;\n }\n return true;\n};\n```\n\n---\n\n## SSR Considerations\n\n> **Note**\n> The service itself is SSR-safe, but your `tokenGetter` must handle server environments:\n\n```typescript\n// ✅ SSR-safe tokenGetter\nprovideJwtService({\n tokenGetter: () => {\n if (typeof localStorage === 'undefined') return '';\n return localStorage.getItem('token') ?? '';\n }\n})\n\n// ✅ Better: Use cookies (available on server)\nprovideJwtService({\n tokenGetter: () => cookieService.get('access_token')\n})\n```\n\n---\n\n## Error Handling\n\nThe service throws descriptive errors:\n\n| Error | Cause |\n|-------|-------|\n| `'Token is missing.'` | Empty token from `tokenGetter` |\n| `'Token is not a valid JWT.'` | Token doesn't have 3 dot-separated parts |\n| `'Failed to decode JWT header.'` | Invalid base64 or JSON in header |\n| `'Failed to decode JWT payload.'` | Invalid base64 or JSON in payload |\n\n---\n\n## Security Notes\n\n> **Warning**\n> This service **does not verify JWT signatures**. It only decodes and validates structure/claims. Signature verification should be done server-side."
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
"name": "Local Storage",
|
|
808
|
+
"category": "services",
|
|
809
|
+
"categoryTitle": "Services",
|
|
810
|
+
"dirName": "local-storage-service",
|
|
811
|
+
"routePath": "local-storage-service",
|
|
812
|
+
"importPath": "ngx-oneforall/services/local-storage-service",
|
|
813
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/local-storage-service",
|
|
814
|
+
"description": "Type-safe wrapper around browser localStorage with transformers for different data types.",
|
|
815
|
+
"fullContent": "Type-safe wrapper around browser localStorage with transformers for different data types.\n\n## Features\n\n- **Type-Safe** — Use transformers for JSON, Number, Boolean, Date, Base64\n- **Key Prefix** — Optional prefix for all keys \n- **SSR Safe** — Falls back to in-memory storage on server\n- **New Methods** — `keys()` and `getAll()` for bulk operations\n\n---\n\n## Installation\n\n```typescript\nimport { \n LocalStorageService, \n provideLocalStorage, \n StorageTransformers \n} from 'ngx-oneforall/services/storage';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { LocalStorageService, provideLocalStorage } from 'ngx-oneforall/services/storage';\n\n@Component({\n selector: 'app-demo',\n template: `<p>Name: </p>`,\n providers: [provideLocalStorage()],\n})\nexport class DemoComponent {\n private storage = inject(LocalStorageService);\n name = this.storage.get('user_name') ?? 'Guest';\n\n saveName(value: string) {\n this.storage.set('user_name', value);\n }\n}\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `get<T>(key, transformer?)` | `T \\| undefined` | Get value by key |\n| `set<T>(key, value, transformer?)` | `void` | Set value by key |\n| `has(key)` | `boolean` | Check if key exists |\n| `remove(key)` | `void` | Remove key |\n| `clear()` | `void` | Clear all keys (prefix-aware) |\n| `keys()` | `string[]` | Get all keys |\n| `getAll<T>(transformer?)` | `Map<string, T>` | Get all key-value pairs |\n| `length()` | `number` | Number of stored items |\n\n---\n\n## Transformers\n\n```typescript\nimport { StorageTransformers } from 'ngx-oneforall/services/storage';\n\n// Store as JSON\nstorage.set('user', { name: 'John' }, StorageTransformers.JSON);\nconst user = storage.get('user', StorageTransformers.JSON);\n\n// Store as Number\nstorage.set('count', 42, StorageTransformers.NUMBER);\nconst count = storage.get('count', StorageTransformers.NUMBER);\n```\n\n| Transformer | Type | Description |\n|-------------|------|-------------|\n| `STRING` | `string` | Default, no transformation |\n| `JSON` | `object` | JSON.stringify/parse |\n| `NUMBER` | `number` | Number conversion |\n| `BOOLEAN` | `boolean` | Boolean conversion |\n| `DATE` | `Date` | ISO date string |\n| `BASE64` | `Uint8Array` | Binary data |\n\n---\n\n## Key Prefix\n\n```typescript\n// All keys prefixed with 'app_'\nproviders: [provideLocalStorage('app_')]\n```\n\n---\n\n## SSR Behavior\n\nOn server-side rendering, `LocalStorageService` automatically uses in-memory storage (no errors).\n\n---\n\n## Live Demo"
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"name": "Logger",
|
|
819
|
+
"category": "services",
|
|
820
|
+
"categoryTitle": "Services",
|
|
821
|
+
"dirName": "logger-service",
|
|
822
|
+
"routePath": "logger-service",
|
|
823
|
+
"importPath": "ngx-oneforall/services/logger-service",
|
|
824
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/logger-service",
|
|
825
|
+
"description": "Configurable logging service with support for disabling and custom logger implementations.",
|
|
826
|
+
"fullContent": "Configurable logging service with support for disabling and custom logger implementations.\n\n## Features\n\n- **4 Log Levels** — `log`, `error`, `warn`, `debug`\n- **Disable Logging** — Completely disable in production\n- **Custom Logger** — Replace console with your own implementation (e.g., send to server)\n- **Type-Safe** — Full TypeScript support\n\n---\n\n## Installation\n\n```typescript\nimport { \n LoggerService, \n provideLoggerService,\n DISABLE_LOGGER,\n CUSTOM_LOGGER,\n CustomLogger\n} from 'ngx-oneforall/services/logger';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { LoggerService, provideLoggerService } from 'ngx-oneforall/services/logger';\n\n@Component({\n selector: 'app-demo',\n template: `<button (click)=\"onClick()\">Log</button>`,\n providers: [provideLoggerService()],\n})\nexport class DemoComponent {\n private logger = inject(LoggerService);\n\n onClick() {\n this.logger.log('User clicked button');\n this.logger.debug('Debug info', { timestamp: Date.now() });\n this.logger.warn('This is a warning');\n this.logger.error('Something went wrong!');\n }\n}\n```\n\n---\n\n## API Reference\n\n| Method | Description |\n|--------|-------------|\n| `log(...args)` | Standard console.log |\n| `error(...args)` | console.error |\n| `warn(...args)` | console.warn |\n| `debug(...args)` | console.debug |\n\n---\n\n## Disable Logging\n\nDisable all logging (useful for production):\n\n```typescript\nimport { DISABLE_LOGGER, provideLoggerService } from 'ngx-oneforall/services/logger';\n\nbootstrapApplication(AppComponent, {\n providers: [\n provideLoggerService(),\n { provide: DISABLE_LOGGER, useValue: true },\n ],\n});\n```\n\nWhen disabled, all log methods become no-ops.\n\n---\n\n## Custom Logger\n\nReplace the default console with your own implementation:\n\n```typescript\nimport { CUSTOM_LOGGER, CustomLogger, provideLoggerService } from 'ngx-oneforall/services/logger';\n\nconst serverLogger: CustomLogger = {\n log: (...args) => sendToServer('log', args),\n error: (...args) => sendToServer('error', args),\n warn: (...args) => sendToServer('warn', args),\n debug: (...args) => {}, // Suppress debug in production\n};\n\nbootstrapApplication(AppComponent, {\n providers: [\n provideLoggerService(),\n { provide: CUSTOM_LOGGER, useValue: serverLogger },\n ],\n});\n```\n\n---\n\n## CustomLogger Interface\n\n```typescript\ninterface CustomLogger {\n log: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n}\n```\n\n---\n\n## Priority\n\n1. If `DISABLE_LOGGER` is `true` → All methods are no-ops\n2. If `CUSTOM_LOGGER` is provided → Uses custom implementation\n3. Otherwise → Uses `console` methods\n\n---\n\n## Live Demo\n\n\n\n### Custom Logger Demo"
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
"name": "Network Status",
|
|
830
|
+
"category": "services",
|
|
831
|
+
"categoryTitle": "Services",
|
|
832
|
+
"dirName": "network-status",
|
|
833
|
+
"routePath": "network-status",
|
|
834
|
+
"importPath": "ngx-oneforall/services/network-status",
|
|
835
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/network-status",
|
|
836
|
+
"description": "Monitor browser network connectivity with reactive signals and observables.",
|
|
837
|
+
"fullContent": "Monitor browser network connectivity with reactive signals and observables.\n\n## Features\n\n- **Signal-Based** — `isOnlineSignal` for reactive templates\n- **Observable-Based** — `isOnline$` for RxJS workflows \n- **Boolean Getters** — `isOnline` and `isOffline`\n- **SSR Safe** — Safe checks for window availability\n- **Auto Updates** — Listens to browser online/offline events\n\n---\n\n## Installation\n\n```typescript\nimport { \n NetworkStatusService, \n provideNetworkStatusService \n} from 'ngx-oneforall/services/network-status';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { NetworkStatusService, provideNetworkStatusService } from 'ngx-oneforall/services/network-status';\n\n@Component({\n selector: 'app-demo',\n template: `\n @if (network.isOnlineSignal()) {\n <span class=\"online\">● Online</span>\n } @else {\n <span class=\"offline\">● Offline</span>\n }\n `,\n providers: [provideNetworkStatusService()],\n})\nexport class DemoComponent {\n network = inject(NetworkStatusService);\n}\n```\n\n---\n\n## API Reference\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `isOnline` | `boolean` | Current online status |\n| `isOffline` | `boolean` | Current offline status |\n| `isOnlineSignal` | `Signal<boolean>` | Reactive signal for templates |\n| `isOnline$` | `Observable<boolean>` | Observable stream of status |\n\n---\n\n## Using with RxJS\n\n```typescript\n@Component({...})\nexport class DemoComponent {\n private network = inject(NetworkStatusService);\n\n constructor() {\n this.network.isOnline$.pipe(\n filter(online => !online),\n takeUntilDestroyed()\n ).subscribe(() => {\n this.showOfflineToast();\n });\n }\n}\n```\n\n---\n\n## SSR Behavior\n\nOn server-side rendering:\n- `isOnline` returns `true` (optimistic default)\n- No event listeners are attached \\\n\n---\n\n## Live Demo"
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"name": "Session Storage",
|
|
841
|
+
"category": "services",
|
|
842
|
+
"categoryTitle": "Services",
|
|
843
|
+
"dirName": "session-storage-service",
|
|
844
|
+
"routePath": "session-storage-service",
|
|
845
|
+
"importPath": "ngx-oneforall/services/session-storage-service",
|
|
846
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/session-storage-service",
|
|
847
|
+
"description": "Type-safe wrapper around browser sessionStorage with transformers for different data types.",
|
|
848
|
+
"fullContent": "Type-safe wrapper around browser sessionStorage with transformers for different data types.\n\n## Features\n\n- **Type-Safe** — Use transformers for JSON, Number, Boolean, Date, Base64\n- **Key Prefix** — Optional prefix for all keys \n- **SSR Safe** — Falls back to in-memory storage on server\n- **New Methods** — `keys()` and `getAll()` for bulk operations\n- **Session Scoped** — Data cleared when browser tab closes\n\n---\n\n## Installation\n\n```typescript\nimport { \n SessionStorageService, \n provideSessionStorage, \n StorageTransformers \n} from 'ngx-oneforall/services/storage';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { SessionStorageService, provideSessionStorage } from 'ngx-oneforall/services/storage';\n\n@Component({\n selector: 'app-demo',\n template: `<p>Token: </p>`,\n providers: [provideSessionStorage()],\n})\nexport class DemoComponent {\n private storage = inject(SessionStorageService);\n token = this.storage.get('auth_token') ?? '';\n\n saveToken(value: string) {\n this.storage.set('auth_token', value);\n }\n}\n```\n\n---\n\n## API Reference\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `get<T>(key, transformer?)` | `T \\| undefined` | Get value by key |\n| `set<T>(key, value, transformer?)` | `void` | Set value by key |\n| `has(key)` | `boolean` | Check if key exists |\n| `remove(key)` | `void` | Remove key |\n| `clear()` | `void` | Clear all keys (prefix-aware) |\n| `keys()` | `string[]` | Get all keys |\n| `getAll<T>(transformer?)` | `Map<string, T>` | Get all key-value pairs |\n| `length()` | `number` | Number of stored items |\n\n---\n\n## Transformers\n\n```typescript\nimport { StorageTransformers } from 'ngx-oneforall/services/storage';\n\n// Store as JSON\nstorage.set('session', { id: '123' }, StorageTransformers.JSON);\nconst session = storage.get('session', StorageTransformers.JSON);\n\n// Store as Boolean\nstorage.set('isLoggedIn', true, StorageTransformers.BOOLEAN);\nconst isLoggedIn = storage.get('isLoggedIn', StorageTransformers.BOOLEAN);\n```\n\n| Transformer | Type | Description |\n|-------------|------|-------------|\n| `STRING` | `string` | Default, no transformation |\n| `JSON` | `object` | JSON.stringify/parse |\n| `NUMBER` | `number` | Number conversion |\n| `BOOLEAN` | `boolean` | Boolean conversion |\n| `DATE` | `Date` | ISO date string |\n| `BASE64` | `Uint8Array` | Binary data |\n\n---\n\n## Key Prefix\n\n```typescript\n// All keys prefixed with 'session_'\nproviders: [provideSessionStorage('session_')]\n```\n\n---\n\n## SSR Behavior\n\nOn server-side rendering, `SessionStorageService` automatically uses in-memory storage (no errors).\n\n---\n\n## Local vs Session Storage\n\n| Feature | LocalStorage | SessionStorage |\n|---------|--------------|----------------|\n| Persistence | Until cleared | Until tab closes |\n| Shared | All tabs | Single tab only |\n| Use case | User preferences | Auth tokens, temp data |\n\n---\n\n## Live Demo"
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
"name": "Shortcut",
|
|
852
|
+
"category": "services",
|
|
853
|
+
"categoryTitle": "Services",
|
|
854
|
+
"dirName": "shortcut",
|
|
855
|
+
"routePath": "shortcut",
|
|
856
|
+
"importPath": "ngx-oneforall/services/shortcut",
|
|
857
|
+
"url": "https://love1024.github.io/ngx-oneforall/services/shortcut",
|
|
858
|
+
"description": "Observable-based keyboard shortcut handling with cross-platform modifier support.",
|
|
859
|
+
"fullContent": "Observable-based keyboard shortcut handling with cross-platform modifier support.\n\n## Features\n\n- **Observable API** — Returns `Observable<KeyboardEvent>` for shortcuts\n- **Cross-Platform** — `cmd`/`meta` maps to `ctrl` on non-Apple platforms\n- **Multiple Shortcuts** — Comma-separated: `\"ctrl.s, meta.s\"`\n- **Scoped/Global** — Listen on specific elements or globally\n- **SSR Safe** — No listeners attached on server\n\n---\n\n## Installation\n\n```typescript\nimport { \n ShortcutService, \n provideShortcutService,\n ShortcutOptions \n} from 'ngx-oneforall/services/shortcut';\n```\n\n---\n\n## Basic Usage\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { ShortcutService, provideShortcutService } from 'ngx-oneforall/services/shortcut';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\n@Component({\n selector: 'app-demo',\n template: `<p>Press Ctrl+S to save</p>`,\n providers: [provideShortcutService()],\n})\nexport class DemoComponent {\n private shortcuts = inject(ShortcutService);\n\n constructor() {\n this.shortcuts.observe({ key: 'ctrl.s', isGlobal: true })\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.save());\n }\n\n save() {\n console.log('Saved!');\n }\n}\n```\n\n---\n\n## API Reference\n\n### `observe(options: ShortcutOptions)`\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `key` | `string` | **required** | Shortcut pattern(s), e.g. `\"ctrl.s\"` |\n| `isGlobal` | `boolean` | `false` | Listen on window |\n| `element` | `HTMLElement` | — | Target element (if not global) |\n| `preventDefault` | `boolean` | `true` | Prevent browser default |\n\n---\n\n## Shortcut Patterns\n\n```typescript\n// Single shortcut\n{ key: 'ctrl.s' }\n\n// Multiple shortcuts (either triggers)\n{ key: 'ctrl.s, meta.s' }\n\n// Multiple modifiers\n{ key: 'ctrl.shift.n' }\n\n// Arrow keys and special keys\n{ key: 'ctrl.arrowup' }\n{ key: 'escape' }\n{ key: 'enter' }\n```\n\n---\n\n## Supported Keys\n\n### Modifiers\n`ctrl`, `shift`, `alt`, `meta` (cmd), `control`\n\n### Special Keys\n`enter`, `escape` (esc), `space`, `tab`, `backspace`, `delete`\n\n### Arrow Keys\n`arrowup` (up), `arrowdown` (down), `arrowleft` (left), `arrowright` (right)\n\n### Punctuation\n`period` (.), `comma` (,), `slash` (/), `minus` (-), `equal` (=)\n\n---\n\n## Cross-Platform Shortcuts\n\n```typescript\n// Works on both Mac (Cmd+S) and Windows/Linux (Ctrl+S)\n{ key: 'ctrl.s, meta.s' }\n\n// On non-Apple platforms, 'cmd' auto-maps to 'ctrl'\n{ key: 'cmd.s' } // → ctrl.s on Windows\n```\n\n---\n\n## Element-Scoped Shortcuts\n\n```typescript\n@ViewChild('editor') editor!: ElementRef;\n\nngAfterViewInit() {\n this.shortcuts.observe({\n key: 'ctrl.enter',\n element: this.editor.nativeElement,\n isGlobal: false,\n }).subscribe(() => this.submit());\n}\n```\n\n---\n\n## Live Demo"
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"name": "Breakpoint Matcher",
|
|
863
|
+
"category": "signals",
|
|
864
|
+
"categoryTitle": "Signals",
|
|
865
|
+
"dirName": "breakpoint-matcher",
|
|
866
|
+
"routePath": "breakpoint-matcher",
|
|
867
|
+
"importPath": "ngx-oneforall/signals/breakpoint-matcher",
|
|
868
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/breakpoint-matcher",
|
|
869
|
+
"description": "Use breakpointMatcher to reactively adapt your UI based on viewport size without manual event listeners.",
|
|
870
|
+
"fullContent": "`breakpointMatcher` creates a reactive signal that tracks viewport size against media queries. It simplifies responsive design by providing real-time breakpoint matching with Angular signals.\n\n## Usage\n\nUse `breakpointMatcher` to reactively adapt your UI based on viewport size without manual event listeners.\n\n{{ NgDocActions.demo(\"BreakpointMatcherSignalDemoComponent\", { container: true }) }}\n\n### Single Breakpoint\n\n```typescript\nimport { breakpointMatcher } from 'ngx-oneforall/signals/breakpoint-matcher';\nimport { BREAKPOINT } from 'ngx-oneforall/constants';\n\n@Component({ ... })\nexport class ResponsiveComponent {\n // True when viewport matches 'md' breakpoint\n isMedium = breakpointMatcher(BREAKPOINT.MD);\n \n // Or use a custom media query\n isMobile = breakpointMatcher('(max-width: 600px)');\n}\n```\n\n### Multiple Breakpoints\n\nFor checking multiple breakpoints at once, use `breakpointMatcherMultiple`:\n\n{{ NgDocActions.demo(\"BreakpointMatcherMultipleSignalDemoComponent\", { container: true }) }}\n\n```typescript\nimport { breakpointMatcherMultiple } from 'ngx-oneforall/signals/breakpoint-matcher';\nimport { BREAKPOINT } from 'ngx-oneforall/constants';\n\n@Component({ ... })\nexport class LayoutComponent {\n breakpoints = breakpointMatcherMultiple([\n BREAKPOINT.XS, \n BREAKPOINT.SM_ONLY\n ]);\n \n // Access results\n // breakpoints().some - true if at least one matches\n // breakpoints().all - true if all match\n // breakpoints().breakpoints[BREAKPOINT.XS] - individual status\n}\n```\n\n## API\n\n### breakpointMatcher\n\n`breakpointMatcher(query: string | BREAKPOINT): Signal<boolean>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `query` | `string \\| BREAKPOINT` | Media query or predefined breakpoint |\n\nReturns a signal that is `true` when the viewport matches.\n\n### breakpointMatcherMultiple\n\n`breakpointMatcherMultiple(queries: (string | BREAKPOINT)[]): Signal<BreakpointResult>`\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `some` | `boolean` | True if at least one breakpoint matches |\n| `all` | `boolean` | True if all breakpoints match |\n| `breakpoints` | `Record<string, boolean>` | Individual match status |\n\n## Predefined Breakpoints\n\nThe `ngx-oneforall/constants` package provides standard breakpoints:\n\n## When to Use\n\n✅ **Good use cases:**\n- Responsive navigation menus\n- Conditional component loading\n- Layout switching (grid/list)\n- Touch vs mouse interactions\n\n❌ **Avoid when:**\n- CSS media queries are sufficient\n- You only need container queries"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"name": "Debounced",
|
|
874
|
+
"category": "signals",
|
|
875
|
+
"categoryTitle": "Signals",
|
|
876
|
+
"dirName": "debounced-signal",
|
|
877
|
+
"routePath": "debounced-signal",
|
|
878
|
+
"importPath": "ngx-oneforall/signals/debounced-signal",
|
|
879
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/debounced-signal",
|
|
880
|
+
"description": "Use debouncedSignal to wait for rapid changes to settle before reacting.",
|
|
881
|
+
"fullContent": "`debouncedSignal` creates a read-only signal that delays updates until the source signal stops changing for a specified duration. Ideal for search inputs, form validation, and window resize handling.\n\n## Usage\n\nUse `debouncedSignal` to wait for rapid changes to settle before reacting.\n\n{{ NgDocActions.demo(\"DebouncedSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { signal } from '@angular/core';\nimport { debouncedSignal } from 'ngx-oneforall/signals/debounced-signal';\n\n@Component({ ... })\nexport class SearchComponent {\n searchTerm = signal('');\n \n // Updates only after user stops typing for 500ms\n debouncedTerm = debouncedSignal(this.searchTerm, 500);\n \n constructor() {\n effect(() => {\n const term = this.debouncedTerm();\n if (term) {\n this.performSearch(term);\n }\n });\n }\n}\n```\n\n## API\n\n`debouncedSignal<T>(source: Signal<T>, delay: number): Signal<T>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `source` | `Signal<T>` | The source signal to debounce |\n| `delay` | `number` | Delay in milliseconds |\n\nReturns a read-only signal that reflects the source value after the delay.\n\n> **Note**\n> The internal timer is automatically cleaned up when the injection context is destroyed.\n\n## When to Use\n\n✅ **Good use cases:**\n- Search input with API calls\n- Form validation on change\n- Window resize handlers\n- Auto-save functionality\n\n❌ **Avoid when:**\n- You need immediate response\n- You want rate limiting instead (use `throttledSignal`)"
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
"name": "Deep Computed",
|
|
885
|
+
"category": "signals",
|
|
886
|
+
"categoryTitle": "Signals",
|
|
887
|
+
"dirName": "deep-computed",
|
|
888
|
+
"routePath": "deep-computed",
|
|
889
|
+
"importPath": "ngx-oneforall/signals/deep-computed",
|
|
890
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/deep-computed",
|
|
891
|
+
"description": "Use deepComputed when you have complex nested objects in signals and want individual property access.",
|
|
892
|
+
"fullContent": "`deepComputed` creates a computed signal that allows readonly nested property access using proxy syntax. This is useful for accessing deeply nested properties as signals, rather than repeatedly calling the root signal.\n\n> **Note**\n> If you need writable nested properties, use `stateSignal` instead.\n\n## Usage\n\nUse `deepComputed` when you have complex nested objects in signals and want individual property access.\n\n{{ NgDocActions.demo(\"DeepComputedDemoComponent\", { container: true }) }}\n\n\n\n### Basic Example\n\n```typescript\nimport { signal, computed } from '@angular/core';\nimport { deepComputed } from 'ngx-oneforall/signals/deep-computed';\n\n@Component({ ... })\nexport class MyComponent {\n user = signal({ profile: { name: 'John', age: 30 } });\n userComputed = deepComputed(() => this.user());\n\n // Access nested properties as signals\n name = this.userComputed.profile.name; // Signal<string>\n \n ngOnInit() {\n console.log(this.name()); // 'John'\n }\n}\n```\n\n\n\n### Reactive Updates\n\n```typescript\nuser = signal({ profile: { name: 'John' } });\ndeep = deepComputed(() => this.user());\n\nconsole.log(deep.profile.name()); // 'John'\n\nuser.set({ profile: { name: 'Jane' } });\nconsole.log(deep.profile.name()); // 'Jane' - automatically reactive\n```\n\n## API\n\n`deepComputed<T>(factory: () => T): DeepComputed<T>`\n\n- **factory**: A computation function that returns an object.\n\nReturns a proxy-wrapped computed signal that provides nested signal access.\n\n### How It Works\n\n- **Signal Access**: Each nested property returns a computed signal\n- **Proxy Recursion**: Nested objects are recursively wrapped in `deepComputed`\n- **Caching**: Signals and proxies are cached for performance\n- **Type Safety**: Full TypeScript support with proper type inference\n\n> **Note**\n> `deepComputed` only works with plain objects. Arrays and built-in types (Date, Map, etc.) are returned as regular signals.\n\n## When to Use\n\n✅ **Good use cases:**\n- Complex nested state from stores\n- Deeply nested API responses\n- Avoiding repetitive signal calls\n\n❌ **Avoid when:**\n- State is flat or simple\n- Performance is critical (adds proxy overhead)\n- Working with arrays or collections"
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
"name": "DOM Event",
|
|
896
|
+
"category": "signals",
|
|
897
|
+
"categoryTitle": "Signals",
|
|
898
|
+
"dirName": "event-signal",
|
|
899
|
+
"routePath": "event-signal",
|
|
900
|
+
"importPath": "ngx-oneforall/signals/event-signal",
|
|
901
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/event-signal",
|
|
902
|
+
"description": "Use eventSignal to track DOM events reactively. Must be called within an injection context.",
|
|
903
|
+
"fullContent": "`eventSignal` creates a reactive signal from DOM events. It automatically handles event listener setup, cleanup, and Angular zone execution.\n\n## Usage\n\nUse `eventSignal` to track DOM events reactively. Must be called within an injection context.\n\n{{ NgDocActions.demo(\"EventSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { eventSignal } from 'ngx-oneforall/signals/event-signal';\n\n@Component({ ... })\nexport class ClickTrackerComponent {\n // Track clicks on the document\n clickEvent = eventSignal(document, 'click');\n \n constructor() {\n effect(() => {\n const event = this.clickEvent();\n if (event) {\n console.log('Clicked at:', event.clientX, event.clientY);\n }\n });\n }\n}\n```\n\n### With Element Reference\n\n```typescript\n@Component({\n template: `<button #btn>Click me</button>`\n})\nexport class MyComponent {\n private elementRef = inject(ElementRef);\n \n // Listen on host element\n hostClick = eventSignal(this.elementRef.nativeElement, 'click');\n}\n```\n\n## API\n\n`eventSignal<T = Event>(target: EventTarget, eventName: string, options?: AddEventListenerOptions): WritableSignal<T | null>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `target` | `EventTarget` | DOM element or EventTarget to listen on |\n| `eventName` | `string` | Event name (e.g., 'click', 'mousemove') |\n| `options` | `AddEventListenerOptions` | Optional listener options |\n\nReturns a writable signal that holds the latest event, or `null` before first event.\n\n> **Note**\n> Must be called in an injection context (constructor, field initializer). For elements not available at construction (like `viewChild`), use `runInInjectionContext` in `ngAfterViewInit`.\n\n## When to Use\n\n✅ **Good use cases:**\n- Mouse/touch tracking\n- Keyboard shortcuts\n- Scroll position monitoring\n- Custom drag-and-drop\n\n❌ **Avoid when:**\n- Using Angular's built-in event binding is sufficient\n- You need complex event composition (use RxJS `fromEvent`)"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
"name": "Interval",
|
|
907
|
+
"category": "signals",
|
|
908
|
+
"categoryTitle": "Signals",
|
|
909
|
+
"dirName": "interval-signal",
|
|
910
|
+
"routePath": "interval-signal",
|
|
911
|
+
"importPath": "ngx-oneforall/signals/interval-signal",
|
|
912
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/interval-signal",
|
|
913
|
+
"description": "Use intervalSignal to create timers, countdowns, or periodic updates with start/stop control.",
|
|
914
|
+
"fullContent": "`intervalSignal` creates a controllable interval timer that updates a signal. It runs the timer outside Angular's zone for performance and only triggers change detection when updating the signal.\n\n## Usage\n\nUse `intervalSignal` to create timers, countdowns, or periodic updates with start/stop control.\n\n{{ NgDocActions.demo(\"IntervalSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { intervalSignal } from 'ngx-oneforall/signals/interval-signal';\n\n@Component({ ... })\nexport class TimerComponent {\n // Ticks every 1000ms (1 second)\n timer = intervalSignal(1000);\n \n constructor() {\n effect(() => {\n console.log('Tick:', this.timer.value());\n });\n }\n \n start() {\n this.timer.start();\n }\n \n stop() {\n this.timer.stop();\n }\n}\n```\n\n## API\n\n`intervalSignal(ms: number): IntervalController`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `ms` | `number` | Interval duration in milliseconds |\n\n### IntervalController\n\nThe returned object provides:\n\n| Property/Method | Type | Description |\n|-----------------|------|-------------|\n| `value` | `WritableSignal<number>` | Current tick count (starts at 0) |\n| `running` | `WritableSignal<boolean>` | Whether the timer is active |\n| `start()` | `() => void` | Starts the interval |\n| `stop()` | `() => void` | Stops the interval |\n\n> **Note**\n> The interval automatically cleans up when the injection context is destroyed.\n\n## When to Use\n\n✅ **Good use cases:**\n- Countdown timers\n- Auto-refresh data polling\n- Animation frame timing\n- Session timeout warnings\n\n❌ **Avoid when:**\n- You need one-time delays (use `setTimeout`)\n- You're polling an API (use RxJS `timer` with HTTP)"
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
"name": "Route Params",
|
|
918
|
+
"category": "signals",
|
|
919
|
+
"categoryTitle": "Signals",
|
|
920
|
+
"dirName": "route-param-signal",
|
|
921
|
+
"routePath": "route-param-signal",
|
|
922
|
+
"importPath": "ngx-oneforall/signals/route-param-signal",
|
|
923
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/route-param-signal",
|
|
924
|
+
"description": "Use routeParamSignal to reactively access route parameters in signal-based components.",
|
|
925
|
+
"fullContent": "`routeParamSignal` creates a reactive signal that tracks route parameters. It automatically updates when the URL's route parameters change, eliminating manual subscriptions.\n\n## Usage\n\nUse `routeParamSignal` to reactively access route parameters in signal-based components.\n\n### Single Parameter\n\n```typescript\nimport { routeParamSignal } from 'ngx-oneforall/signals/route-param-signal';\n\n@Component({ ... })\nexport class ProductDetailComponent {\n // Tracks the 'id' route parameter\n productId = routeParamSignal('id');\n \n constructor() {\n effect(() => {\n const id = this.productId();\n if (id) {\n this.loadProduct(id);\n }\n });\n }\n}\n```\n\n### All Parameters\n\n```typescript\nimport { routeParamsMapSignal } from 'ngx-oneforall/signals/route-param-signal';\n\n@Component({ ... })\nexport class RouteInfoComponent {\n // Get all route params as ParamMap\n params = routeParamsMapSignal();\n \n constructor() {\n effect(() => {\n const map = this.params();\n console.log('Category:', map.get('category'));\n console.log('ID:', map.get('id'));\n });\n }\n}\n```\n\n## API\n\n### routeParamSignal\n\n`routeParamSignal(paramName: string): Signal<string | null>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `paramName` | `string` | Name of the route parameter |\n\nReturns a signal with the current parameter value, or `null` if not present.\n\n### routeParamsMapSignal\n\n`routeParamsMapSignal(): Signal<ParamMap>`\n\nReturns a signal containing the full `ParamMap` of route parameters.\n\n> **Note**\n> Both signals automatically update when navigation changes the route parameters.\n\n## When to Use\n\n✅ **Good use cases:**\n- Detail pages (`/products/:id`)\n- Nested routes with parameters\n- Dynamic route segments\n- Master-detail layouts\n\n❌ **Avoid when:**\n- You need query parameters (use `routeQueryParamSignal`)\n- You need route data, not params (use `ActivatedRoute.data`)"
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
"name": "Route Query",
|
|
929
|
+
"category": "signals",
|
|
930
|
+
"categoryTitle": "Signals",
|
|
931
|
+
"dirName": "route-query-param-signal",
|
|
932
|
+
"routePath": "route-query-param-signal",
|
|
933
|
+
"importPath": "ngx-oneforall/signals/route-query-param-signal",
|
|
934
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/route-query-param-signal",
|
|
935
|
+
"description": "Use routeQueryParamSignal to reactively access query parameters in signal-based components.",
|
|
936
|
+
"fullContent": "`routeQueryParamSignal` creates a reactive signal that tracks URL query parameters. It automatically updates when query strings change, eliminating manual subscriptions.\n\n## Usage\n\nUse `routeQueryParamSignal` to reactively access query parameters in signal-based components.\n\n### Single Query Parameter\n\n```typescript\nimport { routeQueryParamSignal } from 'ngx-oneforall/signals/route-query-param-signal';\n\n@Component({ ... })\nexport class SearchComponent {\n // Tracks the 'q' query parameter (?q=value)\n searchTerm = routeQueryParamSignal('q');\n \n constructor() {\n effect(() => {\n const term = this.searchTerm();\n if (term) {\n this.performSearch(term);\n }\n });\n }\n}\n```\n\n### All Query Parameters\n\n```typescript\nimport { routeQueryParamsMapSignal } from 'ngx-oneforall/signals/route-query-param-signal';\n\n@Component({ ... })\nexport class FilterComponent {\n // Get all query params as ParamMap\n queryParams = routeQueryParamsMapSignal();\n \n constructor() {\n effect(() => {\n const map = this.queryParams();\n console.log('Sort:', map.get('sort'));\n console.log('Page:', map.get('page'));\n });\n }\n}\n```\n\n## API\n\n### routeQueryParamSignal\n\n`routeQueryParamSignal(paramName: string): Signal<string | null>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `paramName` | `string` | Name of the query parameter |\n\nReturns a signal with the current parameter value, or `null` if not present.\n\n### routeQueryParamsMapSignal\n\n`routeQueryParamsMapSignal(): Signal<ParamMap>`\n\nReturns a signal containing the full `ParamMap` of query parameters.\n\n> **Note**\n> Both signals automatically update when navigation changes the query string.\n\n## When to Use\n\n✅ **Good use cases:**\n- Search pages (`?q=angular`)\n- Filter and sort controls\n- Pagination (`?page=2`)\n- Shareable URLs with state\n\n❌ **Avoid when:**\n- You need route path parameters (use `routeParamSignal`)\n- You need fragment data (use `ActivatedRoute.fragment`)"
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
"name": "Router Event",
|
|
940
|
+
"category": "signals",
|
|
941
|
+
"categoryTitle": "Signals",
|
|
942
|
+
"dirName": "router-event-signal",
|
|
943
|
+
"routePath": "router-event-signal",
|
|
944
|
+
"importPath": "ngx-oneforall/signals/router-event-signal",
|
|
945
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/router-event-signal",
|
|
946
|
+
"description": "Use routerEventSignal to react to navigation changes with Angular signals.",
|
|
947
|
+
"fullContent": "`routerEventSignal` creates a reactive signal that tracks Angular Router events. It provides easy access to the current event and computed helpers for common navigation states.\n\n## Usage\n\nUse `routerEventSignal` to react to navigation changes with Angular signals.\n\n{{ NgDocActions.demo(\"RouterEventSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { routerEventSignal } from 'ngx-oneforall/signals/router-event-signal';\n\n@Component({ ... })\nexport class NavigationComponent {\n router = routerEventSignal();\n \n constructor() {\n effect(() => {\n if (this.router.isNavigationEnd()) {\n console.log('Navigation complete!');\n this.trackPageView();\n }\n });\n }\n}\n```\n\n### Loading Indicator\n\n```typescript\n@Component({\n template: `\n @if (router.isNavigationStart()) {\n <div class=\"loading\">Loading...</div>\n }\n `\n})\nexport class AppComponent {\n router = routerEventSignal();\n}\n```\n\n## API\n\n`routerEventSignal(): RouterEventState`\n\n### RouterEventState\n\nThe returned object provides:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `event` | `Signal<RouterEvent \\| null>` | Most recent router event |\n| `isNavigationStart` | `Signal<boolean>` | True during navigation start |\n| `isNavigationEnd` | `Signal<boolean>` | True after navigation completes |\n\n> **Note**\n> The subscription is automatically cleaned up when the injection context is destroyed.\n\n## When to Use\n\n✅ **Good use cases:**\n- Loading indicators during navigation\n- Analytics/page view tracking\n- Navigation guards with signals\n- Scroll position restoration\n\n❌ **Avoid when:**\n- You need detailed route data (use `ActivatedRoute`)\n- You need to prevent navigation (use route guards)"
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
"name": "State",
|
|
951
|
+
"category": "signals",
|
|
952
|
+
"categoryTitle": "Signals",
|
|
953
|
+
"dirName": "state-signal",
|
|
954
|
+
"routePath": "state-signal",
|
|
955
|
+
"importPath": "ngx-oneforall/signals/state-signal",
|
|
956
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/state-signal",
|
|
957
|
+
"description": "Use stateSignal when you have complex nested objects and want ergonomic property access with the ability to update nested values directly.",
|
|
958
|
+
"fullContent": "`stateSignal` creates a deep writable signal that allows nested property access and updates using proxy syntax. Updates to nested properties automatically propagate (bubble) up to the root signal.\n\n## Usage\n\nUse `stateSignal` when you have complex nested objects and want ergonomic property access with the ability to update nested values directly.\n\n{{ NgDocActions.demo(\"StateSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { stateSignal } from 'ngx-oneforall/signals/state-signal';\n\n@Component({ ... })\nexport class MyComponent {\n state = stateSignal({ \n user: { \n name: 'John', \n age: 30 \n } \n });\n\n // Access nested properties as signals\n name = this.state.user.name; // StateSignal<string>\n \n ngOnInit() {\n console.log(this.name()); // 'John'\n \n // Update nested property - automatically bubbles to root\n this.name.set('Jane');\n console.log(this.state().user.name); // 'Jane'\n }\n}\n```\n\n### Nested Updates with Bubbling\n\n```typescript\nstate = stateSignal({ \n profile: { \n address: { \n city: 'New York' \n } \n } \n});\n\n// Direct nested update\nstate.profile.address.city.set('Los Angeles');\n\n// Root signal is updated automatically\nconsole.log(state().profile.address.city); // 'Los Angeles'\n\n// Use update() for derived values\nstate.profile.address.city.update(city => city.toUpperCase());\n```\n\n### Using with Existing Signal\n\n```typescript\nimport { signal } from '@angular/core';\nimport { stateSignal } from 'ngx-oneforall/signals/state-signal';\n\n// Wrap an existing signal\nconst source = signal({ count: 0 });\nconst state = stateSignal(source);\n\nstate.count.set(10);\nconsole.log(source().count); // 10 - source is updated\n```\n\n## API\n\n`stateSignal<T>(initialValue: T | WritableSignal<T>, onUpdate?: (value: T) => void): StateSignal<T>`\n\n- **initialValue**: An object or an existing `WritableSignal` to wrap\n- **onUpdate**: Optional callback invoked when the signal is updated (used internally for bubbling)\n\nReturns a proxy-wrapped writable signal that provides nested signal access with update propagation.\n\n### Available Methods\n\n- `set(value)` - Replace the value at any level\n- `update(fn)` - Update based on current value\n- `asReadonly()` - Get a readonly version of the signal\n- `()` - Read the current value\n\n### How It Works\n\n- **Nested Signals**: Each nested property returns a writable `StateSignal`\n- **Bubbling**: Updates at any level propagate to the root with new object references\n- **Caching**: Nested signals are cached for performance\n- **Type Safety**: Full TypeScript support with proper type inference\n\n> **Note**\n> `stateSignal` only recurses into plain objects. Arrays are treated as single signals and not recursed into element-by-element.\n\n## When to Use\n\n✅ **Good use cases:**\n- Complex nested form state\n- Deeply nested configuration objects\n- When you need to update specific nested properties without manually spreading\n\n❌ **Avoid when:**\n- State is flat or simple\n- Working primarily with arrays (use regular signals)\n- Performance is critical (adds proxy overhead)\n\n## Comparison with deepComputed\n\n| Feature | `stateSignal` | `deepComputed` |\n|---------|---------------|----------------|\n| **Writable** | ✅ Yes | ❌ Read-only |\n| **Bubbling** | ✅ Updates propagate to root | N/A |\n| **Use case** | Mutable nested state | Derived nested state |"
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
"name": "Storage",
|
|
962
|
+
"category": "signals",
|
|
963
|
+
"categoryTitle": "Signals",
|
|
964
|
+
"dirName": "storage-signal",
|
|
965
|
+
"routePath": "storage-signal",
|
|
966
|
+
"importPath": "ngx-oneforall/signals/storage-signal",
|
|
967
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/storage-signal",
|
|
968
|
+
"description": "Use storageSignal to persist state across page refreshes or share state between tabs.",
|
|
969
|
+
"fullContent": "`storageSignal` creates a reactive signal that automatically syncs with browser storage (`localStorage` or `sessionStorage`). Changes to the signal persist to storage, and the signal can optionally sync across browser tabs.\n\n## Usage\n\nUse `storageSignal` to persist state across page refreshes or share state between tabs.\n\n{{ NgDocActions.demo(\"StorageSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { storageSignal } from 'ngx-oneforall/signals/storage-signal';\n\n@Component({ ... })\nexport class MyComponent {\n // Persists to localStorage under key 'counter'\n counter = storageSignal<number>('counter', 0);\n\n increment() {\n this.counter.update(c => c + 1);\n // Value is automatically saved to localStorage\n }\n}\n```\n\n> **Note**\n> The signal must be created within an injection context (e.g., constructor, field initializer) or you must provide an `injector` in options.\n\n### Using Session Storage\n\n```typescript\n// Use sessionStorage instead of localStorage\nconst token = storageSignal<string>('session-token', '', { \n storage: sessionStorage \n});\n```\n\n### Cross-Tab Synchronization\n\n```typescript\n// Changes in one tab will reflect in all open tabs\nconst cart = storageSignal<string[]>('cart', [], { \n crossTabSync: true \n});\n```\n\n### Custom Serialization\n\n```typescript\ninterface User {\n id: number;\n name: string;\n}\n\nconst user = storageSignal<User>('current-user', { id: 0, name: '' }, {\n serializer: (value) => JSON.stringify(value),\n deserializer: (data) => JSON.parse(data)\n});\n```\n\n## API\n\n`storageSignal<T>(key: string, defaultValue: T, options?: StorageSignalOptions<T>): WritableSignal<T>`\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `key` | `string` | The storage key to use |\n| `defaultValue` | `T` | Initial value if nothing in storage |\n| `options` | `StorageSignalOptions<T>` | Optional configuration |\n\n### Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `storage` | `Storage` | `localStorage` | Storage backend (`localStorage`, `sessionStorage`, or custom) |\n| `serializer` | `(v: T) => string` | `JSON.stringify` | Function to serialize value to string |\n| `deserializer` | `(data: string) => T` | `JSON.parse` | Function to deserialize string to value |\n| `crossTabSync` | `boolean` | `false` | Sync changes across browser tabs |\n| `injector` | `Injector` | Current injector | Angular injector for use outside injection context |\n\n## When to Use\n\n✅ **Good use cases:**\n- User preferences (theme, language)\n- Form draft auto-save\n- Shopping cart persistence\n- Authentication tokens\n\n❌ **Avoid when:**\n- Storing sensitive data (use secure cookies instead)\n- Large datasets (storage limits apply)\n- Data that changes very frequently (storage writes are synchronous)"
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
"name": "Throttled",
|
|
973
|
+
"category": "signals",
|
|
974
|
+
"categoryTitle": "Signals",
|
|
975
|
+
"dirName": "throttled-signal",
|
|
976
|
+
"routePath": "throttled-signal",
|
|
977
|
+
"importPath": "ngx-oneforall/signals/throttled-signal",
|
|
978
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/throttled-signal",
|
|
979
|
+
"description": "Use throttledSignal when you need to limit the rate of updates from high-frequency events like scroll, mousemove, or resize.",
|
|
980
|
+
"fullContent": "`throttledSignal` creates a read-only signal that limits how often the source signal's updates are emitted. It ensures updates occur at most once per specified interval, regardless of how frequently the source changes.\n\n## Usage\n\nUse `throttledSignal` when you need to limit the rate of updates from high-frequency events like scroll, mousemove, or resize.\n\n{{ NgDocActions.demo(\"ThrottledSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { signal } from '@angular/core';\nimport { throttledSignal } from 'ngx-oneforall/signals/throttled-signal';\n\n@Component({ ... })\nexport class MouseTrackerComponent {\n coords = signal('0, 0');\n \n // Updates at most once every 100ms\n throttledCoords = throttledSignal(this.coords, 100);\n \n onMouseMove(event: MouseEvent) {\n this.coords.set(`${event.clientX}, ${event.clientY}`);\n }\n}\n```\n\n## API\n\n`throttledSignal<T>(source: Signal<T>, delay: number): Signal<T>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `source` | `Signal<T>` | The source signal to throttle |\n| `delay` | `number` | Minimum interval between updates (ms) |\n\nReturns a read-only signal that updates at most once per `delay` interval.\n\n> **Note**\n> The internal timer is automatically cleaned up when the injection context is destroyed.\n\n## Debounce vs Throttle\n\n| Behavior | `debouncedSignal` | `throttledSignal` |\n|----------|-------------------|-------------------|\n| **When it emits** | After source stops changing | At regular intervals |\n| **Use case** | Wait for input to settle | Rate-limit frequent updates |\n| **Example** | Search input | Scroll position tracking |\n\n## When to Use\n\n✅ **Good use cases:**\n- Scroll event handling\n- Mouse movement tracking\n- Window resize handlers\n- Progress updates\n\n❌ **Avoid when:**\n- You need to wait for input to settle (use `debouncedSignal`)\n- You need immediate response to every change"
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
"name": "WebSocket",
|
|
984
|
+
"category": "signals",
|
|
985
|
+
"categoryTitle": "Signals",
|
|
986
|
+
"dirName": "websocket-signal",
|
|
987
|
+
"routePath": "websocket-signal",
|
|
988
|
+
"importPath": "ngx-oneforall/signals/websocket-signal",
|
|
989
|
+
"url": "https://love1024.github.io/ngx-oneforall/signals/websocket-signal",
|
|
990
|
+
"description": "Use webSocketSignal to integrate real-time WebSocket features with Angular's signal-based reactivity.",
|
|
991
|
+
"fullContent": "`webSocketSignal` creates a reactive interface for WebSocket connections. It manages the connection lifecycle and provides signals for messages, status, and errors.\n\n## Usage\n\nUse `webSocketSignal` to integrate real-time WebSocket features with Angular's signal-based reactivity.\n\n{{ NgDocActions.demo(\"WebSocketSignalDemoComponent\", { container: true }) }}\n\n### Basic Example\n\n```typescript\nimport { webSocketSignal } from 'ngx-oneforall/signals/websocket-signal';\n\n@Component({ ... })\nexport class ChatComponent {\n socket = webSocketSignal<string>('wss://echo.websocket.org');\n \n constructor() {\n effect(() => {\n const msg = this.socket.messages();\n if (msg) {\n console.log('Received:', msg);\n }\n });\n }\n \n send(text: string) {\n if (this.socket.status() === 'open') {\n this.socket.send(text);\n }\n }\n}\n```\n\n### Handling Connection Status\n\n```typescript\n@Component({\n template: `\n <div [class]=\"socket.status()\">\n Status: socket.status().toUpperCase() ' }}\n </div>\n @if (socket.status() === 'open') {\n <button (click)=\"socket.close()\">Disconnect</button>\n }\n `\n})\nexport class StatusComponent {\n socket = webSocketSignal('wss://example.com');\n}\n```\n\n## API\n\n`webSocketSignal<T>(url: string): WebSocketState<T>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `url` | `string` | WebSocket server URL |\n\n### WebSocketState\n\nThe returned object provides:\n\n| Property/Method | Type | Description |\n|-----------------|------|-------------|\n| `messages` | `Signal<T \\| null>` | Latest received message |\n| `error` | `Signal<Event \\| null>` | Latest error event |\n| `status` | `Signal<'connecting' \\| 'open' \\| 'closed' \\| 'error'>` | Connection status |\n| `send(msg)` | `(msg: T) => void` | Send a message |\n| `close()` | `() => void` | Close the connection |\n\n> **Note**\n> The connection is automatically closed when the injection context is destroyed.\n\n## When to Use\n\n✅ **Good use cases:**\n- Real-time chat applications\n- Live notifications\n- Stock/crypto price feeds\n- Collaborative editing\n\n❌ **Avoid when:**\n- You need request/response patterns (use HTTP)\n- Server doesn't support WebSocket\n- You need complex reconnection logic (use dedicated libraries)"
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
"name": "Callable",
|
|
995
|
+
"category": "types",
|
|
996
|
+
"categoryTitle": "Types",
|
|
997
|
+
"dirName": "callable",
|
|
998
|
+
"routePath": "callable",
|
|
999
|
+
"importPath": "ngx-oneforall/types/callable",
|
|
1000
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/callable",
|
|
1001
|
+
"description": "Use Callable when you need to define a generic function type with specific arguments or return type, essentially a shorthand for { (...args: Args): Return }.",
|
|
1002
|
+
"fullContent": "`Callable` is a utility type that represents a function signature. It allows you to specify the argument types and return type.\n\n## Usage\n\nUse `Callable` when you need to define a generic function type with specific arguments or return type, essentially a shorthand for `{ (...args: Args): Return }`.\n\n```typescript\nimport { Callable } from 'ngx-oneforall/types';\n\n// Function taking any args and returning any\nconst fn: Callable = () => {};\n\n// Function taking string and number, returning boolean\nconst specificFn: Callable<[string, number], boolean> = (str, num) => {\n return true;\n};\n```\n\n## API\n\n`Callable<Args extends any[] = any[], Return = any>`\n\n- **Args**: Tuple definition of argument types. Default is `any[]`.\n- **Return**: Return type. Default is `any`."
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"name": "DeepPartial",
|
|
1006
|
+
"category": "types",
|
|
1007
|
+
"categoryTitle": "Types",
|
|
1008
|
+
"dirName": "deep-partial",
|
|
1009
|
+
"routePath": "deep-partial",
|
|
1010
|
+
"importPath": "ngx-oneforall/types/deep-partial",
|
|
1011
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/deep-partial",
|
|
1012
|
+
"description": "Use DeepPartial when you need to construct an object that might only have some deep properties defined, for example when mocking data in tests or applying partial updates.",
|
|
1013
|
+
"fullContent": "`DeepPartial` is a utility type that recursively makes all properties of a type and its nested objects optional. This is similar to `Partial<T>`, but applies deeply.\n\n## Usage\n\nUse `DeepPartial` when you need to construct an object that might only have some deep properties defined, for example when mocking data in tests or applying partial updates.\n\n```typescript\nimport { DeepPartial } from 'ngx-oneforall/types';\n\ninterface Config {\n theme: {\n color: string;\n darkMode: boolean;\n };\n api: {\n endpoint: string;\n retries: number;\n };\n}\n\n// Valid\nconst partialConfig: DeepPartial<Config> = {\n theme: {\n darkMode: true\n }\n // api can be undefined\n // theme.color can be undefined\n};\n```\n\n## API\n\n`DeepPartial<T>`\n\n- **T**: The source type to make deeply partial."
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
"name": "IsArrowFunction",
|
|
1017
|
+
"category": "types",
|
|
1018
|
+
"categoryTitle": "Types",
|
|
1019
|
+
"dirName": "is-arrow-function",
|
|
1020
|
+
"routePath": "is-arrow-function",
|
|
1021
|
+
"importPath": "ngx-oneforall/types/is-arrow-function",
|
|
1022
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/is-arrow-function",
|
|
1023
|
+
"description": "Use IsArrowFunction when you need to conditionally type based on whether a function is an arrow function or a standard function.",
|
|
1024
|
+
"fullContent": "`IsArrowFunction` is a utility type that determines if a given type is an arrow function. It returns `true` if the type is an arrow function (doesn't have a `this` context), and `false` otherwise.\n\n## Usage\n\nUse `IsArrowFunction` when you need to conditionally type based on whether a function is an arrow function or a standard function.\n\n```typescript\nimport { IsArrowFunction } from 'ngx-oneforall/types';\n\nconst arrow = () => {};\nfunction standard() {}\n\ntype CheckArrow = IsArrowFunction<typeof arrow>; // true\ntype CheckStandard = IsArrowFunction<typeof standard>; // false\n```\n\n## API\n\n`IsArrowFunction<T>`\n\n- **T**: The type to check.\n\nReturns `true` or `false`."
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
"name": "KeysOfType",
|
|
1028
|
+
"category": "types",
|
|
1029
|
+
"categoryTitle": "Types",
|
|
1030
|
+
"dirName": "keys-of-type",
|
|
1031
|
+
"routePath": "keys-of-type",
|
|
1032
|
+
"importPath": "ngx-oneforall/types/keys-of-type",
|
|
1033
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/keys-of-type",
|
|
1034
|
+
"description": "Use KeysOfType to filter keys of an object based on their value types.",
|
|
1035
|
+
"fullContent": "`KeysOfType` is a utility type that extracts the keys from a type `T` where the value extends the type `U`.\n\n## Usage\n\nUse `KeysOfType` to filter keys of an object based on their value types.\n\n```typescript\nimport { KeysOfType } from 'ngx-oneforall/types';\n\ninterface User {\n id: number;\n name: string;\n isActive: boolean;\n age: number;\n}\n\n// Result: 'id' | 'age'\ntype NumberKeys = KeysOfType<User, number>;\n\n// Result: 'name'\ntype StringKeys = KeysOfType<User, string>;\n```\n\n## API\n\n`KeysOfType<T, U>`\n\n- **T**: The source type to extract keys from.\n- **U**: The type that the value must extend."
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
"name": "OmitByValue",
|
|
1039
|
+
"category": "types",
|
|
1040
|
+
"categoryTitle": "Types",
|
|
1041
|
+
"dirName": "omit-by-value",
|
|
1042
|
+
"routePath": "omit-by-value",
|
|
1043
|
+
"importPath": "ngx-oneforall/types/omit-by-value",
|
|
1044
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/omit-by-value",
|
|
1045
|
+
"description": "Use OmitByValue when you want to exclude properties of a specific type from an object.",
|
|
1046
|
+
"fullContent": "`OmitByValue` is a utility type that constructs a new type by omitting properties from type `T` where the value extends type `V`. It combines `Omit` and `KeysOfType`.\n\n## Usage\n\nUse `OmitByValue` when you want to exclude properties of a specific type from an object.\n\n```typescript\nimport { OmitByValue } from 'ngx-oneforall/types';\n\ninterface User {\n id: number;\n name: string;\n isActive: boolean;\n age: number;\n description: string;\n}\n\n// Result: { name: string; isActive: boolean; description: string; }\ntype NonNumericUserProps = OmitByValue<User, number>;\n```\n\n## API\n\n`OmitByValue<T, V>`\n\n- **T**: The source type.\n- **V**: The type to omit values by."
|
|
1047
|
+
},
|
|
1048
|
+
{
|
|
1049
|
+
"name": "PartialOnly",
|
|
1050
|
+
"category": "types",
|
|
1051
|
+
"categoryTitle": "Types",
|
|
1052
|
+
"dirName": "partial-only",
|
|
1053
|
+
"routePath": "partial-only",
|
|
1054
|
+
"importPath": "ngx-oneforall/types/partial-only",
|
|
1055
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/partial-only",
|
|
1056
|
+
"description": "Use PartialOnly when you need a subset of a type where the selected properties should be optional.",
|
|
1057
|
+
"fullContent": "`PartialOnly` is a utility type that picks specified properties from a type and makes them optional, while removing all other properties. It effectively combines `Pick` and `Partial`.\n\n## Usage\n\nUse `PartialOnly` when you need a subset of a type where the selected properties should be optional.\n\n```typescript\nimport { PartialOnly } from 'ngx-oneforall/types';\n\ninterface User {\n id: number;\n name: string;\n email: string;\n age: number;\n}\n\n// Result: { name?: string; email?: string; }\ntype UserUpdate = PartialOnly<User, 'name' | 'email'>;\n```\n\n## API\n\n`PartialOnly<T, K extends keyof T>`\n\n- **T**: The source type.\n- **K**: The keys to pick and make partial."
|
|
1058
|
+
},
|
|
1059
|
+
{
|
|
1060
|
+
"name": "PickByValue",
|
|
1061
|
+
"category": "types",
|
|
1062
|
+
"categoryTitle": "Types",
|
|
1063
|
+
"dirName": "pick-by-value",
|
|
1064
|
+
"routePath": "pick-by-value",
|
|
1065
|
+
"importPath": "ngx-oneforall/types/pick-by-value",
|
|
1066
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/pick-by-value",
|
|
1067
|
+
"description": "Use PickByValue when you want to create a new object type containing only properties of a specific type.",
|
|
1068
|
+
"fullContent": "`PickByValue` is a utility type that constructs a new type by picking properties from type `T` where the value extends type `V`. It combines `Pick` and `KeysOfType`.\n\n## Usage\n\nUse `PickByValue` when you want to create a new object type containing only properties of a specific type.\n\n```typescript\nimport { PickByValue } from 'ngx-oneforall/types';\n\ninterface User {\n id: number;\n name: string;\n isActive: boolean;\n age: number;\n}\n\n// Result: { id: number; age: number; }\ntype NumericUserProps = PickByValue<User, number>;\n```\n\n## API\n\n`PickByValue<T, V>`\n\n- **T**: The source type.\n- **V**: The type to filter values by."
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
"name": "RequiredOnly",
|
|
1072
|
+
"category": "types",
|
|
1073
|
+
"categoryTitle": "Types",
|
|
1074
|
+
"dirName": "required-only",
|
|
1075
|
+
"routePath": "required-only",
|
|
1076
|
+
"importPath": "ngx-oneforall/types/required-only",
|
|
1077
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/required-only",
|
|
1078
|
+
"description": "Use RequiredOnly when you need a subset of a type where the selected properties must be present and non-optional.",
|
|
1079
|
+
"fullContent": "`RequiredOnly` is a utility type that makes specified properties of a type required, while removing all other properties. It effectively combines `Pick` and `Required`.\n\n## Usage\n\nUse `RequiredOnly` when you need a subset of a type where the selected properties must be present and non-optional.\n\n```typescript\nimport { RequiredOnly } from 'ngx-oneforall/types';\n\ninterface User {\n id: number;\n name?: string;\n email?: string;\n age?: number;\n}\n\n// Result: { name: string; email: string; }\ntype UserContact = RequiredOnly<User, 'name' | 'email'>;\n```\n\n## API\n\n`RequiredOnly<T, K extends keyof T>`\n\n- **T**: The source type.\n- **K**: The keys to pick and make required."
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
"name": "Simple Changes",
|
|
1083
|
+
"category": "types",
|
|
1084
|
+
"categoryTitle": "Types",
|
|
1085
|
+
"dirName": "simple-changes",
|
|
1086
|
+
"routePath": "simple-changes",
|
|
1087
|
+
"importPath": "ngx-oneforall/types/simple-changes",
|
|
1088
|
+
"url": "https://love1024.github.io/ngx-oneforall/types/simple-changes",
|
|
1089
|
+
"description": "A type-safe version of Angular's SimpleChanges that provides proper typing for ngOnChanges lifecycle hook. Eliminates the need for type assertions when accessing change properties.",
|
|
1090
|
+
"fullContent": "A type-safe version of Angular's `SimpleChanges` that provides proper typing for `ngOnChanges` lifecycle hook. Eliminates the need for type assertions when accessing change properties.\n\n## Usage\n\n```typescript\nimport { SimpleChangesTyped } from 'ngx-oneforall/types';\n```\n\n## API\n\n```typescript\ntype SimpleChangesTyped<T> = {\n [P in keyof T]?: ComponentChange<T, P>;\n};\n\ninterface ComponentChange<T, P extends keyof T> {\n previousValue: T[P];\n currentValue: T[P];\n firstChange: boolean;\n isFirstChange(): boolean;\n}\n```\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `previousValue` | `T[P]` | The previous value before the change |\n| `currentValue` | `T[P]` | The current value after the change |\n| `firstChange` | `boolean` | True if this is the initial binding |\n| `isFirstChange()` | `() => boolean` | Returns true if this is the initial binding |\n\n> **Note**\n> All properties are optional (`?`) since not all inputs change on every `ngOnChanges` cycle.\n\n## Example\n\n```typescript\n@Component({\n selector: 'app-user',\n template: `<p></p>`\n})\nexport class UserComponent implements OnChanges {\n @Input() name!: string;\n @Input() age!: number;\n\n ngOnChanges(changes: SimpleChangesTyped<UserComponent>) {\n if (changes.name) {\n // TypeScript knows these are strings\n console.log('Name:', changes.name.previousValue, '→', changes.name.currentValue);\n }\n\n if (changes.age?.firstChange) {\n // TypeScript knows this is a number\n console.log('Initial age:', changes.age.currentValue);\n }\n }\n}\n```\n\n## Comparison\n\n```typescript\n// ❌ Without SimpleChangesTyped\nngOnChanges(changes: SimpleChanges) {\n if (changes['name']) {\n const prev = changes['name'].previousValue as string; // Manual cast\n }\n}\n\n// ✅ With SimpleChangesTyped\nngOnChanges(changes: SimpleChangesTyped<MyComponent>) {\n if (changes.name) {\n const prev = changes.name.previousValue; // Automatically typed as string\n }\n}\n```\n\n## Use Cases\n\n- **Type-safe change detection**: Access previous/current values without casting\n- **Autocomplete support**: IDE provides suggestions for available properties\n- **Refactoring safety**: Rename refactoring works correctly across components\n- **Better error detection**: Catch typos at compile time"
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
"name": "Base64 URL",
|
|
1094
|
+
"category": "utils",
|
|
1095
|
+
"categoryTitle": "Utils",
|
|
1096
|
+
"dirName": "base64-url",
|
|
1097
|
+
"routePath": "base64-url",
|
|
1098
|
+
"importPath": "ngx-oneforall/utils/base64-url",
|
|
1099
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/base64-url",
|
|
1100
|
+
"description": "URL-safe Base64 encoding utilities for safely transmitting data in URLs, query parameters, and tokens.",
|
|
1101
|
+
"fullContent": "URL-safe Base64 encoding utilities for safely transmitting data in URLs, query parameters, and tokens.\n\n## Usage\n\nImport the functions from the base64 utility:\n\n```typescript\nimport { base64UrlEncode, base64UrlDecode } from 'ngx-oneforall/utils/base64';\n```\n\n### Encoding\n\n```typescript\nconst encoded = base64UrlEncode('Hello, 世界!');\n// Result: \"SGVsbG8sIOS4lueVjCE\"\n```\n\n### Decoding\n\n```typescript\nconst decoded = base64UrlDecode('SGVsbG8sIOS4lueVjCE');\n// Result: \"Hello, 世界!\"\n```\n\n## API\n\n| Function | Description |\n|----------|-------------|\n| `base64UrlEncode(value: string)` | Encodes a UTF-8 string to URL-safe base64 (RFC 4648) |\n| `base64UrlDecode(value: string)` | Decodes a URL-safe base64 string to UTF-8 |\n\n> **Note**\n> These utilities correctly handle multi-byte Unicode characters (e.g., Chinese, emoji) using `TextEncoder`/`TextDecoder`.\n\n## Use Cases\n\n- **JWT Tokens**: Encode/decode JWT payload segments\n- **Query Parameters**: Safely embed binary data in URLs\n- **OAuth State**: Encode state parameters for OAuth flows\n- **Data URIs**: Create URL-safe data identifiers\n\n## Live Demo"
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
"name": "Download Link",
|
|
1105
|
+
"category": "utils",
|
|
1106
|
+
"categoryTitle": "Utils",
|
|
1107
|
+
"dirName": "download-link",
|
|
1108
|
+
"routePath": "download-link",
|
|
1109
|
+
"importPath": "ngx-oneforall/utils/download-link",
|
|
1110
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/download-link",
|
|
1111
|
+
"description": "Use downloadLink when you have a file URL (or Blob URL) and want to initiate a download action, for example from a button click or after an API response.",
|
|
1112
|
+
"fullContent": "`downloadLink` is a utility function that programmatically triggers a file download by creating a temporary anchor element.\n\n## Usage\n\nUse `downloadLink` when you have a file URL (or Blob URL) and want to initiate a download action, for example from a button click or after an API response.\n\n{{ NgDocActions.demo(\"DownloadLinkDemoComponent\", { container: true }) }}\n\n### Example\n\n```typescript\nimport { downloadLink } from 'ngx-oneforall/utils/download-link';\n\n// Download a remote file\ndownloadLink('https://example.com/report.pdf', 'report.pdf');\n\n// Download a generated blob\nconst blob = new Blob(['content'], { type: 'text/plain' });\nconst url = URL.createObjectURL(blob);\ndownloadLink(url, 'note.txt');\n```\n\n## API\n\n`downloadLink(url: string, fileName: string = 'download'): void`\n\n- **url**: The URL of the file to download. Can be a remote URL or a blob URL.\n- **fileName**: The name to suggest for the downloaded file. Defaults to `'download'`.\n\n> **Note**\n> For cross-origin URLs, the `download` attribute might be ignored by browsers for security reasons, resulting in navigation instead of download unless the server sends appropriate `Content-Disposition` headers."
|
|
1113
|
+
},
|
|
1114
|
+
{
|
|
1115
|
+
"name": "File to Base64",
|
|
1116
|
+
"category": "utils",
|
|
1117
|
+
"categoryTitle": "Utils",
|
|
1118
|
+
"dirName": "file-base64",
|
|
1119
|
+
"routePath": "file-base64",
|
|
1120
|
+
"importPath": "ngx-oneforall/utils/file-base64",
|
|
1121
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/file-base64",
|
|
1122
|
+
"description": "Converts a File object to a base64-encoded data URL string asynchronously.",
|
|
1123
|
+
"fullContent": "Converts a `File` object to a base64-encoded data URL string asynchronously.\n\n## Usage\n\n```typescript\nimport { fileToBase64 } from 'ngx-oneforall/utils/base64';\n```\n\n### Basic Example\n\n```typescript\nasync onFileChange(event: Event) {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n \n if (file) {\n const dataUrl = await fileToBase64(file);\n // dataUrl: \"data:image/png;base64,iVBORw0KGgo...\"\n }\n}\n```\n\n### Angular Template\n\n```html\n<input type=\"file\" (change)=\"onFileChange($event)\">\n<img [src]=\"imagePreview\" *ngIf=\"imagePreview\">\n```\n\n## API\n\n`fileToBase64(file: File): Promise<string>`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `file` | `File` | The file object from an input element |\n| **Returns** | `Promise<string>` | Data URL (e.g., `data:image/png;base64,...`) |\n\n## Use Cases\n\n- **Image Previews**: Display uploaded images before submission\n- **File Uploads**: Convert files to base64 for API transmission\n- **Avatar Editors**: Create inline image previews\n- **Form Data**: Store file content in JSON payloads\n\n## Live Demo"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
"name": "Find Type",
|
|
1127
|
+
"category": "utils",
|
|
1128
|
+
"categoryTitle": "Utils",
|
|
1129
|
+
"dirName": "find-type",
|
|
1130
|
+
"routePath": "find-type",
|
|
1131
|
+
"importPath": "ngx-oneforall/utils/find-type",
|
|
1132
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/find-type",
|
|
1133
|
+
"description": "Comprehensive type detection utility that returns a Types enum value for any JavaScript value. Supports all primitives, collections, typed arrays, and iterators.",
|
|
1134
|
+
"fullContent": "Comprehensive type detection utility that returns a `Types` enum value for any JavaScript value. Supports all primitives, collections, typed arrays, and iterators.\n\n## Usage\n\n```typescript\nimport { findType } from 'ngx-oneforall/utils/find-type';\nimport { Types } from 'ngx-oneforall/constants';\n\nfindType(42); // Types.Number\nfindType('hello'); // Types.String\nfindType(BigInt(123)); // Types.BigInt\nfindType(new Map()); // Types.Map\n```\n\n## Supported Types\n\n| Category | Types |\n|----------|-------|\n| **Primitives** | `Null`, `Undefined`, `Boolean`, `String`, `Number`, `BigInt`, `Symbol` |\n| **Functions** | `Function`, `GeneratorFunction` |\n| **Collections** | `Array`, `Map`, `WeakMap`, `Set`, `WeakSet` |\n| **Typed Arrays** | `Int8Array`, `Uint8Array`, `Uint8ClampedArray`, `Int16Array`, `Uint16Array`, `Int32Array`, `Uint32Array`, `Float32Array`, `Float64Array` |\n| **Iterators** | `MapIterator`, `SetIterator`, `StringIterator`, `ArrayIterator`, `GeneratorObject` |\n| **Fallback** | `Object` (for plain objects and class instances) |\n\n## Quick Examples\n\n```typescript\nfindType(null); // Types.Null\nfindType(undefined); // Types.Undefined\nfindType(true); // Types.Boolean\nfindType(42); // Types.Number\nfindType(BigInt(999)); // Types.BigInt\nfindType(Symbol('id')); // Types.Symbol\nfindType(() => {}); // Types.Function\nfindType(function* () {}); // Types.GeneratorFunction\nfindType([1, 2, 3]); // Types.Array\nfindType(new Map()); // Types.Map\nfindType(new Set()); // Types.Set\nfindType(new Int8Array()); // Types.Int8Array\nfindType({}); // Types.Object\n```\n\n## Type Guard Helpers\n\nAll type checking functions are also exported as type guards:\n\n```typescript\nimport { isString, isNumber, isBigInt, isArray, isMap } from 'ngx-oneforall/utils/find-type';\n\nconst value: unknown = getData();\n\nif (isString(value)) {\n console.log(value.toUpperCase()); // TypeScript knows it's string\n}\n\nif (isArray(value)) {\n console.log(value.length); // TypeScript knows it's unknown[]\n}\n```\n\n## Available Type Guards\n\n| Function | Type Guard |\n|----------|------------|\n| `isNull(v)` | `v is null` |\n| `isUndefined(v)` | `v is undefined` |\n| `isBoolean(v)` | `v is boolean` |\n| `isString(v)` | `v is string` |\n| `isNumber(v)` | `v is number` |\n| `isBigInt(v)` | `v is bigint` |\n| `isSymbol(v)` | `v is symbol` |\n| `isFunction(v)` | `v is (...args) => any` |\n| `isArray(v)` | `v is unknown[]` |\n| `isMap(v)` | `v is Map<unknown, unknown>` |\n| `isSet(v)` | `v is Set<unknown>` |\n| `isDate(v)` | `v is Date` |\n| `isRegexp(v)` | `v is RegExp` |\n| `isError(v)` | `v is Error` |\n\n> **Note**\n> Detection order is optimized for common types first. More specific types (like `GeneratorFunction`) are checked before general ones (like `Function`).\n\n## Use Cases\n\n- **API validation**: Check data types from external sources\n- **Dynamic rendering**: Render different UI based on value type\n- **Form handling**: Validate input values before processing\n- **Debugging**: Log precise runtime types"
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
"name": "Hash",
|
|
1138
|
+
"category": "utils",
|
|
1139
|
+
"categoryTitle": "Utils",
|
|
1140
|
+
"dirName": "hash",
|
|
1141
|
+
"routePath": "hash",
|
|
1142
|
+
"importPath": "ngx-oneforall/utils/hash",
|
|
1143
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/hash",
|
|
1144
|
+
"description": "Fast, non-cryptographic string hashing utilities for generating numeric hash codes.",
|
|
1145
|
+
"fullContent": "Fast, non-cryptographic string hashing utilities for generating numeric hash codes.\n\n## Usage\n\n```typescript\nimport { hashCode, hashCodeWithSalt } from 'ngx-oneforall/utils/hash';\n```\n\n### Basic Hashing\n\n```typescript\nconst hash = hashCode('hello');\n// hash: -1794106052\n```\n\n### Salted Hashing\n\n```typescript\nconst hash = hashCodeWithSalt('hello', 'my-secret-salt');\n// Different result than hashCode('hello')\n```\n\n## API\n\n| Function | Description |\n|----------|-------------|\n| `hashCode(str: string)` | Generates a 32-bit signed integer hash |\n| `hashCodeWithSalt(str: string, salt: string)` | Generates a salted hash using the salt's hash as seed |\n\n## Algorithm\n\nUses the DJB2-like algorithm, equivalent to Java's `String.hashCode()`:\n\n```\nhash = ((hash << 5) - hash + charCode) | 0\n = (hash * 31 + charCode) | 0\n```\n\nThe `| 0` ensures 32-bit signed integer truncation.\n\n## Use Cases\n\n- **Cache Keys**: Generate numeric keys for caching mechanisms\n- **Hash Tables**: Distribute objects across buckets\n- **Quick Comparison**: Fast string equality pre-check\n- **Partitioning**: Consistent assignment to shards/partitions\n\n> **Note**\n> This is a non-cryptographic hash. Do not use for passwords, security tokens, or any security-sensitive application. Use `crypto` or `bcrypt` instead.\n\n## Example: Cache Key Generation\n\n```typescript\nfunction getCacheKey(userId: string, resource: string): number {\n return hashCode(`${userId}:${resource}`);\n}\n\nconst key = getCacheKey('user-123', 'profile');\ncache.set(key, data);\n```\n\n## Example: Consistent Partitioning\n\n```typescript\nfunction getPartition(key: string, partitionCount: number): number {\n return Math.abs(hashCode(key)) % partitionCount;\n}\n\nconst partition = getPartition('order-456', 8);\n// Always returns same partition for same key\n```"
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
"name": "Host Platform",
|
|
1149
|
+
"category": "utils",
|
|
1150
|
+
"categoryTitle": "Utils",
|
|
1151
|
+
"dirName": "host-platform",
|
|
1152
|
+
"routePath": "host-platform",
|
|
1153
|
+
"importPath": "ngx-oneforall/utils/host-platform",
|
|
1154
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/host-platform",
|
|
1155
|
+
"description": "Detects the host platform/operating system based on the user agent string. SSR-safe with modern iPadOS 13+ detection.",
|
|
1156
|
+
"fullContent": "---\nkeyword: HostPlatformPage\n---\n\nDetects the host platform/operating system based on the user agent string. SSR-safe with modern iPadOS 13+ detection.\n\n## Usage\n\n```typescript\nimport { getHostPlatform } from 'ngx-oneforall/utils/host-platform';\nimport { HostPlatform } from 'ngx-oneforall/constants';\n\nconst platform = getHostPlatform();\n\nif (platform === HostPlatform.IOS) {\n // iOS-specific logic (includes iPad)\n}\n```\n\n## API\n\n`getHostPlatform(): HostPlatform`\n\nReturns one of the following enum values:\n\n| Value | Description |\n|-------|-------------|\n| `HostPlatform.MAC` | macOS desktop |\n| `HostPlatform.IOS` | iPhone, iPad, iPod (including iPadOS 13+) |\n| `HostPlatform.WINDOWS` | Windows desktop |\n| `HostPlatform.WINDOWS_PHONE` | Windows Phone |\n| `HostPlatform.ANDROID` | Android devices |\n| `HostPlatform.LINUX` | Linux distributions |\n| `HostPlatform.UNKNOWN` | SSR or unrecognized platform |\n\n> **Note**\n> iPadOS 13+ reports as \"Macintosh\" in the user agent. This utility uses touch detection to correctly identify iPads.\n\n## Use Cases\n\n- **Platform-specific UI**: Show different layouts for mobile vs desktop\n- **Feature detection**: Enable/disable features based on platform\n- **Analytics**: Track user platform distribution\n- **Download links**: Show appropriate app store links\n\n## Example: Conditional Rendering\n\n```typescript\n@Component({...})\nexport class AppComponent {\n platform = getHostPlatform();\n \n get isMobile(): boolean {\n return [HostPlatform.IOS, HostPlatform.ANDROID].includes(this.platform);\n }\n}\n```\n\n## Demo\n\n{{ NgDocActions.demo(\"HostPlatformDemoComponent\", {container: true}) }}"
|
|
1157
|
+
},
|
|
1158
|
+
{
|
|
1159
|
+
"name": "Is Key Defined",
|
|
1160
|
+
"category": "utils",
|
|
1161
|
+
"categoryTitle": "Utils",
|
|
1162
|
+
"dirName": "is-key-defined",
|
|
1163
|
+
"routePath": "is-key-defined",
|
|
1164
|
+
"importPath": "ngx-oneforall/utils/is-key-defined",
|
|
1165
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/is-key-defined",
|
|
1166
|
+
"description": "Type guard utility that checks if an object has a defined (non-undefined) value for a given key, with TypeScript type narrowing.",
|
|
1167
|
+
"fullContent": "Type guard utility that checks if an object has a defined (non-undefined) value for a given key, with TypeScript type narrowing.\n\n## Usage\n\n```typescript\nimport { isKeyDefined } from 'ngx-oneforall/utils/is-key-defined';\n\nconst user = { name: 'John', age: undefined };\n\nif (isKeyDefined(user, 'name')) {\n console.log(user.name.toUpperCase()); // TypeScript knows name is defined\n}\n```\n\n## API\n\n```typescript\nisKeyDefined<T extends object, K extends keyof T>(\n obj: T,\n key: K,\n ownPropertyOnly?: boolean\n): obj is T & Record<K, NonNullable<T[K]>>\n```\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `obj` | `T` | - | The object to check |\n| `key` | `keyof T` | - | The key to check for |\n| `ownPropertyOnly` | `boolean` | `true` | Only check own properties, exclude inherited |\n\n> **Note**\n> This function acts as a type guard—when it returns `true`, TypeScript narrows the type to guarantee the key's value is non-nullable.\n\n## Use Cases\n\n- **Safe property access**: Prevent \"cannot read property of undefined\" errors\n- **Form validation**: Verify required fields are present\n- **API responses**: Safely access dynamic object properties\n- **Type narrowing**: Let TypeScript know a property is defined\n\n## Example: Including Inherited Properties\n\n```typescript\nclass Base { inherited = 'value'; }\nclass Child extends Base { own = 'child'; }\n\nconst child = new Child();\n\n// Default: only own properties\nisKeyDefined(child, 'own'); // true\nisKeyDefined(child, 'inherited'); // false (it's inherited)\n\n// Include inherited\nisKeyDefined(child, 'inherited', false); // true\n```\n\n## Example: Guarding Object Access\n\n```typescript\ninterface Config {\n apiUrl?: string;\n timeout?: number;\n}\n\nfunction initializeApi(config: Config) {\n if (isKeyDefined(config, 'apiUrl')) {\n // TypeScript knows config.apiUrl is string, not undefined\n fetch(config.apiUrl);\n }\n}\n```"
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
"name": "Is Number",
|
|
1171
|
+
"category": "utils",
|
|
1172
|
+
"categoryTitle": "Utils",
|
|
1173
|
+
"dirName": "is-number",
|
|
1174
|
+
"routePath": "is-number",
|
|
1175
|
+
"importPath": "ngx-oneforall/utils/is-number",
|
|
1176
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/is-number",
|
|
1177
|
+
"description": "Type guard utilities for validating numeric values. Provides robust checking for number primitives, numeric strings, and Number objects.",
|
|
1178
|
+
"fullContent": "Type guard utilities for validating numeric values. Provides robust checking for number primitives, numeric strings, and Number objects.\n\n## Usage\n\n```typescript\nimport { isNumberValue, isNumberString, isNumeric, isNumberObject } from 'ngx-oneforall/utils/is-number';\n```\n\n## API\n\n| Function | Returns `true` for | Returns `false` for |\n|----------|-------------------|---------------------|\n| `isNumberValue(value)` | Finite number primitives | `NaN`, `Infinity`, strings, objects |\n| `isNumberString(value)` | Strings parseable as numbers | Empty strings, whitespace, non-numeric |\n| `isNumberObject(value)` | `new Number()` objects | Primitives, other objects |\n| `isNumeric(value)` | Numbers OR numeric strings | Everything else |\n\n## Quick Examples\n\n```typescript\n// isNumberValue - finite number primitives only\nisNumberValue(42); // true\nisNumberValue(3.14); // true\nisNumberValue(NaN); // false\nisNumberValue(Infinity); // false\nisNumberValue('42'); // false\n\n// isNumberString - valid numeric strings\nisNumberString('42'); // true\nisNumberString('3.14'); // true\nisNumberString(''); // false\nisNumberString(' '); // false\nisNumberString('abc'); // false\n\n// isNumeric - either number or numeric string\nisNumeric(42); // true\nisNumeric('42'); // true\nisNumeric(null); // false\n```\n\n## Edge Cases\n\n| Input | `isNumberValue` | `isNumberString` | `isNumeric` |\n|-------|-----------------|------------------|-------------|\n| `42` | ✅ | ❌ | ✅ |\n| `'42'` | ❌ | ✅ | ✅ |\n| `NaN` | ❌ | ❌ | ❌ |\n| `Infinity` | ❌ | ❌ | ❌ |\n| `''` | ❌ | ❌ | ❌ |\n| `' '` | ❌ | ❌ | ❌ |\n| `null` | ❌ | ❌ | ❌ |\n| `new Number(42)` | ❌ | ❌ | ❌ |\n\n> **Note**\n> `isNumeric` does NOT include `Number` objects. Use `isNumberObject` separately if needed.\n\n## Use Cases\n\n- **Form Validation**: Validate numeric input fields\n- **Type Narrowing**: Let TypeScript know a value is a number\n- **API Responses**: Safely handle mixed `number | string` data\n- **Data Parsing**: Check before `parseInt` or `parseFloat`\n\n## Example: Safe Numeric Parsing\n\n```typescript\nfunction parseValue(input: unknown): number | null {\n if (isNumberValue(input)) {\n return input; // Already a number\n }\n if (isNumberString(input)) {\n return parseFloat(input);\n }\n return null;\n}\n\nparseValue(42); // 42\nparseValue('3.14'); // 3.14\nparseValue('abc'); // null\n```\n\n## Example: Type-Safe Calculation\n\n```typescript\nfunction double(value: unknown): number | null {\n if (isNumeric(value)) {\n const num = typeof value === 'string' ? parseFloat(value) : value;\n return num * 2;\n }\n return null;\n}\n```"
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
"name": "Is Present",
|
|
1182
|
+
"category": "utils",
|
|
1183
|
+
"categoryTitle": "Utils",
|
|
1184
|
+
"dirName": "is-present",
|
|
1185
|
+
"routePath": "is-present",
|
|
1186
|
+
"importPath": "ngx-oneforall/utils/is-present",
|
|
1187
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/is-present",
|
|
1188
|
+
"description": "Type guard utility that checks if a value is neither null nor undefined. Narrows the type to NonNullable<T>.",
|
|
1189
|
+
"fullContent": "Type guard utility that checks if a value is neither `null` nor `undefined`. Narrows the type to `NonNullable<T>`.\n\n## Usage\n\n```typescript\nimport { isPresent } from 'ngx-oneforall/utils/is-present';\n```\n\n## API\n\n`isPresent<T>(value: T): value is NonNullable<T>`\n\nReturns `true` if value is not `null` and not `undefined`.\n\n| Input | Result |\n|-------|--------|\n| `'hello'` | ✅ `true` |\n| `0` | ✅ `true` |\n| `false` | ✅ `true` |\n| `''` | ✅ `true` |\n| `null` | ❌ `false` |\n| `undefined` | ❌ `false` |\n\n> **Note**\n> Falsy values like `0`, `false`, and `''` are considered \"present\" since they are not nullish.\n\n## Example: Type Narrowing\n\n```typescript\nconst value: string | null | undefined = getValue();\n\nif (isPresent(value)) {\n console.log(value.toUpperCase()); // TypeScript knows value is string\n}\n```\n\n## Example: Array Filtering\n\n```typescript\nconst items = [1, null, 2, undefined, 3];\nconst filtered = items.filter(isPresent);\n// filtered: number[] = [1, 2, 3]\n```\n\n## Example: Optional Chaining Alternative\n\n```typescript\n// Instead of:\nif (user?.profile?.name !== undefined && user?.profile?.name !== null) {\n // ...\n}\n\n// Use:\nif (isPresent(user?.profile?.name)) {\n // TypeScript narrows type correctly\n}\n```\n\n## Use Cases\n\n- **Array cleanup**: Filter out null/undefined from arrays\n- **Type narrowing**: Let TypeScript know a value is defined\n- **Form validation**: Check if optional values are present\n- **API responses**: Safely access potentially null data"
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
"name": "Is Record",
|
|
1193
|
+
"category": "utils",
|
|
1194
|
+
"categoryTitle": "Utils",
|
|
1195
|
+
"dirName": "is-record",
|
|
1196
|
+
"routePath": "is-record",
|
|
1197
|
+
"importPath": "ngx-oneforall/utils/is-record",
|
|
1198
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/is-record",
|
|
1199
|
+
"description": "Type guard that checks if a value is a plain object (record) as opposed to built-in types, arrays, or class instances.",
|
|
1200
|
+
"fullContent": "Type guard that checks if a value is a plain object (record) as opposed to built-in types, arrays, or class instances.\n\n## Usage\n\n```typescript\nimport { isRecord } from 'ngx-oneforall/utils/is-record';\n```\n\n## API\n\n`isRecord(value: unknown): value is Record<string, unknown>`\n\nReturns `true` if value is a plain object, `false` otherwise.\n\n## Quick Examples\n\n```typescript\nisRecord({}); // true\nisRecord({ a: 1, b: 2 }); // true\nisRecord(Object.create(null)); // true (null-prototype)\n\nisRecord([1, 2, 3]); // false (array)\nisRecord(new Date()); // false (built-in)\nisRecord(new Map()); // false (built-in)\nisRecord(new MyClass()); // false (class instance)\nisRecord(null); // false\n```\n\n## Truth Table\n\n| Input | Result | Reason |\n|-------|--------|--------|\n| `{}` | ✅ | Plain object literal |\n| `{ a: 1 }` | ✅ | Plain object with properties |\n| `Object.create(null)` | ✅ | Null-prototype object |\n| `[]` | ❌ | Array |\n| `new Date()` | ❌ | Built-in |\n| `new Map()` | ❌ | Built-in |\n| `new Set()` | ❌ | Built-in |\n| `new Error()` | ❌ | Built-in |\n| `new MyClass()` | ❌ | Class instance |\n| `null` | ❌ | Not an object |\n| `undefined` | ❌ | Not an object |\n\n## Detection Strategy\n\nThe implementation uses a multi-step approach for accuracy and performance:\n\n1. **Fast path**: Check if prototype is `null` or `Object.prototype`\n2. **Built-in exclusion**: Check against known non-record constructors (Date, Map, Set, etc.)\n3. **Fallback**: Use `Object.prototype.toString` for edge cases\n\n> **Note**\n> This implementation explicitly excludes class instances and all JavaScript built-in types including `ArrayBuffer`, `Blob`, `File`, `URL`, and more.\n\n## Example: Type-Safe Iteration\n\n```typescript\nfunction processData(value: unknown) {\n if (isRecord(value)) {\n // TypeScript knows value is Record<string, unknown>\n Object.entries(value).forEach(([key, val]) => {\n console.log(key, val);\n });\n }\n}\n```\n\n## Example: Deep Clone Safety\n\n```typescript\nfunction safeClone(obj: unknown): unknown {\n if (!isRecord(obj)) {\n return obj; // Return primitives/built-ins as-is\n }\n \n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = safeClone(value);\n }\n return result;\n}\n```\n\n## Use Cases\n\n- **Safe object iteration**: Avoid iterating arrays or class instances\n- **Serialization**: Validate objects before JSON.stringify\n- **API validation**: Check if response is a plain object\n- **State management**: Distinguish records from other object types"
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
"name": "Normalize Key",
|
|
1204
|
+
"category": "utils",
|
|
1205
|
+
"categoryTitle": "Utils",
|
|
1206
|
+
"dirName": "normalize-key",
|
|
1207
|
+
"routePath": "normalize-key",
|
|
1208
|
+
"importPath": "ngx-oneforall/utils/normalize-key",
|
|
1209
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/normalize-key",
|
|
1210
|
+
"description": "The normalizeKey utility standardizes keyboard key values across different browsers and platforms. It handles common inconsistencies and maps user-friendly aliases to standard KeyboardEvent.key values.",
|
|
1211
|
+
"fullContent": "---\nkeyword: NormalizeKeyPage\n---\n\nThe `normalizeKey` utility standardizes keyboard key values across different browsers and platforms. It handles common inconsistencies and maps user-friendly aliases to standard `KeyboardEvent.key` values.\n\n## Usage\n\nImport `normalizeKey` from `ngx-oneforall`:\n\n```typescript\nimport {normalizeKey} from 'ngx-oneforall/utils/normalize-key';\n\n// Basic usage\nconst key = normalizeKey('Esc'); // Returns 'escape'\nconst space = normalizeKey('Space'); // Returns ' '\n\n// Platform-specific normalization\n// On Windows/Linux/Android, 'meta' becomes 'control'\nconst meta = normalizeKey('meta'); \n```\n\n## Transformations\n\nThe utility performs the following transformations:\n\n| Input | Output | Description |\n|-------|--------|-------------|\n| `space` | `' '` | Maps the string 'space' to a literal space character |\n| `esc` | `escape` | Standardizes escape key |\n| `up` | `arrowup` | Standardizes arrow keys |\n| `down` | `arrowdown` | |\n| `left` | `arrowleft` | |\n| `right` | `arrowright` | |\n| `altleft` | `alt` | Standardizes alt key |\n| `meta` | `control` | **On non-Apple platforms only** |\n\n## Case Insensitivity\n\nThe function is case-insensitive. Inputs like `ESC`, `Esc`, and `esc` will all return `escape`.\n\n## Demo\n\nType in the input below to see how keys are normalized:\n\n{{ NgDocActions.demo(\"NormalizeKeyDemoComponent\", {container: true}) }}"
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
"name": "Safe Await",
|
|
1215
|
+
"category": "utils",
|
|
1216
|
+
"categoryTitle": "Utils",
|
|
1217
|
+
"dirName": "safe-await",
|
|
1218
|
+
"routePath": "safe-await",
|
|
1219
|
+
"importPath": "ngx-oneforall/utils/safe-await",
|
|
1220
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/safe-await",
|
|
1221
|
+
"description": "Go-style error handling for async operations. Returns a tuple [result, error] instead of throwing, eliminating try/catch blocks.",
|
|
1222
|
+
"fullContent": "Go-style error handling for async operations. Returns a tuple `[result, error]` instead of throwing, eliminating try/catch blocks.\n\n## Usage\n\n```typescript\nimport { safeAwait } from 'ngx-oneforall/utils/safe-await';\n```\n\n## API\n\n```typescript\nsafeAwait<T>(input: Promise<T> | Observable<T>): Promise<[T, null] | [null, Error]>\n```\n\n| Input | Success | Failure |\n|-------|---------|---------|\n| `Promise<T>` | `[result, null]` | `[null, error]` |\n| `Observable<T>` | `[lastValue, null]` | `[null, error]` |\n\n> **Note**\n> Observables are converted using `lastValueFrom`. Empty Observables (complete without emitting) will return an `EmptyError`.\n\n## Quick Example\n\n```typescript\nconst [user, error] = await safeAwait(fetchUser(id));\n\nif (error) {\n console.error('Failed:', error.message);\n return;\n}\n\nconsole.log(user.name); // TypeScript knows user is defined\n```\n\n## Comparison: Traditional vs safeAwait\n\n```typescript\n// ❌ Traditional try/catch\nasync function getUser(id: string) {\n try {\n const user = await fetchUser(id);\n return { user, error: null };\n } catch (error) {\n return { user: null, error };\n }\n}\n\n// ✅ With safeAwait\nasync function getUser(id: string) {\n const [user, error] = await safeAwait(fetchUser(id));\n return { user, error };\n}\n```\n\n## Example: HTTP Request\n\n```typescript\nasync loadData() {\n const [data, error] = await safeAwait(\n this.http.get<User[]>('/api/users')\n );\n\n if (error) {\n this.errorMessage = 'Failed to load users';\n return;\n }\n\n this.users = data;\n}\n```\n\n## Example: Multiple Async Operations\n\n```typescript\nasync saveOrder() {\n const [inventory, invError] = await safeAwait(checkInventory(this.items));\n if (invError) return this.showError('Inventory check failed');\n\n const [payment, payError] = await safeAwait(processPayment(this.total));\n if (payError) return this.showError('Payment failed');\n\n const [order, orderError] = await safeAwait(createOrder(inventory, payment));\n if (orderError) return this.showError('Order creation failed');\n\n return order;\n}\n```\n\n## Use Cases\n\n- **HTTP requests**: Handle API errors without try/catch\n- **Form submission**: Clean async validation and submission\n- **Sequential operations**: Chain multiple async calls with clear error points\n- **Observable integration**: Use with Angular's HttpClient seamlessly"
|
|
1223
|
+
},
|
|
1224
|
+
{
|
|
1225
|
+
"name": "Safe Serialize",
|
|
1226
|
+
"category": "utils",
|
|
1227
|
+
"categoryTitle": "Utils",
|
|
1228
|
+
"dirName": "safe-serialize",
|
|
1229
|
+
"routePath": "safe-serialize",
|
|
1230
|
+
"importPath": "ngx-oneforall/utils/safe-serialize",
|
|
1231
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/safe-serialize",
|
|
1232
|
+
"description": "Safely serializes any JavaScript value to a JSON string, including non-JSON types like functions, symbols, BigInt, and circular references. Produces deterministic output for caching and memoization.",
|
|
1233
|
+
"fullContent": "Safely serializes any JavaScript value to a JSON string, including non-JSON types like functions, symbols, BigInt, and circular references. Produces deterministic output for caching and memoization.\n\n## Usage\n\n```typescript\nimport { safeSerialize } from 'ngx-oneforall/utils/safe-serialize';\n\nconst key = safeSerialize({ name: 'John', count: BigInt(42) });\n// '{\"count\":\"__bigint:42\",\"name\":\"John\"}'\n```\n\n## Serialization Format\n\n| Type | Serialized Format |\n|------|-------------------|\n| Function (named) | `\"__fn:functionName\"` |\n| Function (anonymous) | `\"__fn:anonymous\\|h:hash\"` |\n| Symbol | `\"__sym:Symbol(description)\"` |\n| BigInt | `\"__bigint:123\"` |\n| Date | ISO string (built-in JSON behavior) |\n| RegExp | `{ __type: 'RegExp', value: '/pattern/flags' }` |\n| Error | `{ __type: 'Error', name, message }` |\n| Map | `{ __type: 'Map', entries: [[k, v], ...] }` |\n| Set | `{ __type: 'Set', values: [...] }` |\n| WeakMap | `{ __type: 'WeakMap', note: 'Not iterable' }` |\n| WeakSet | `{ __type: 'WeakSet', note: 'Not iterable' }` |\n| Class instance | `{ __type: 'ClassName', ...props }` |\n| Circular ref | `\"__circular__\"` |\n\n> **Note**\n> Object keys are sorted alphabetically for deterministic output. `{ b: 2, a: 1 }` serializes the same as `{ a: 1, b: 2 }`.\n\n## Quick Examples\n\n```typescript\n// Functions\nsafeSerialize(() => {}); // '\"__fn:anonymous|h:-1234567\"'\n\n// Symbols and BigInt\nsafeSerialize([Symbol('id'), BigInt(999)]);\n// '[\"__sym:Symbol(id)\",\"__bigint:999\"]'\n\n// Circular references\nconst obj = { name: 'root' };\nobj.self = obj;\nsafeSerialize(obj); // '{\"name\":\"root\",\"self\":\"__circular__\"}'\n\n// Map and Set\nsafeSerialize(new Map([['a', 1]]));\n// '{\"__type\":\"Map\",\"entries\":[[\"a\",1]]}'\n```\n\n## Use Cases\n\n- **Memoization keys**: Generate cache keys from any arguments\n- **Argument hashing**: Create stable fingerprints for function calls\n- **Deep comparison**: Compare complex objects by their serialized form\n- **Logging**: Serialize non-JSON values for debugging\n\n## Demo\n\n\n\n## Limitations\n\n- **Not reversible**: Cannot deserialize back to original values\n- **Lossy for functions/symbols**: Only names/descriptions are preserved\n- **WeakMap/WeakSet**: Cannot iterate, serialized with placeholder\n- **Same-name collision**: Different functions with same name produce same output"
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
"name": "Unique Component ID",
|
|
1237
|
+
"category": "utils",
|
|
1238
|
+
"categoryTitle": "Utils",
|
|
1239
|
+
"dirName": "unique-component-id",
|
|
1240
|
+
"routePath": "unique-component-id",
|
|
1241
|
+
"importPath": "ngx-oneforall/utils/unique-component-id",
|
|
1242
|
+
"url": "https://love1024.github.io/ngx-oneforall/utils/unique-component-id",
|
|
1243
|
+
"description": "Generates unique ID strings for Angular components. Useful for form elements, ARIA attributes, and dynamically created components.",
|
|
1244
|
+
"fullContent": "Generates unique ID strings for Angular components. Useful for form elements, ARIA attributes, and dynamically created components.\n\n## Usage\n\n```typescript\nimport { uniqueComponentId } from 'ngx-oneforall/utils/unique-component-id';\n```\n\n## API\n\n`uniqueComponentId(prefix?: string): string`\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `prefix` | `string` | `'id'` | Prefix for the generated ID |\n\nReturns a unique string in the format `{prefix}{counter}`.\n\n```typescript\nuniqueComponentId(); // 'id1'\nuniqueComponentId(); // 'id2'\nuniqueComponentId('btn'); // 'btn1' (independent counter)\nuniqueComponentId('input'); // 'input1' (independent counter)\nuniqueComponentId('btn'); // 'btn2'\n```\n\n> **Note**\n> Each prefix has its own independent counter. `btn1, btn2, input1, input2` instead of a shared global counter.\n\n## Example: Form Label Association\n\n```typescript\n@Component({\n selector: 'app-text-input',\n template: `\n <label [attr.for]=\"inputId\"></label>\n <input [id]=\"inputId\" type=\"text\">\n `\n})\nexport class TextInputComponent {\n @Input() label = '';\n inputId = uniqueComponentId('input');\n}\n```\n\n## Example: ARIA Attributes\n\n```typescript\n@Component({\n selector: 'app-dialog',\n template: `\n <div role=\"dialog\" [attr.aria-labelledby]=\"titleId\">\n <h2 [id]=\"titleId\"></h2>\n <ng-content></ng-content>\n </div>\n `\n})\nexport class DialogComponent {\n @Input() title = '';\n titleId = uniqueComponentId('dialog-title');\n}\n```\n\n## Example: Multiple Instances\n\n```typescript\n@Component({\n selector: 'app-accordion-item',\n template: `\n <button [attr.aria-controls]=\"panelId\" (click)=\"toggle()\">\n \n </button>\n <div [id]=\"panelId\" *ngIf=\"expanded\">\n <ng-content></ng-content>\n </div>\n `\n})\nexport class AccordionItemComponent {\n @Input() header = '';\n panelId = uniqueComponentId('panel');\n expanded = false;\n \n toggle() { this.expanded = !this.expanded; }\n}\n```\n\n## Use Cases\n\n- **Form controls**: Associate labels with inputs via `for`/`id` pairing\n- **ARIA attributes**: `aria-labelledby`, `aria-describedby`, `aria-controls`\n- **Dynamic components**: Ensure unique IDs across multiple instances\n- **Accordion/tabs**: Link triggers to their content panels"
|
|
1245
|
+
},
|
|
1246
|
+
{
|
|
1247
|
+
"name": "Credit Card",
|
|
1248
|
+
"category": "validators",
|
|
1249
|
+
"categoryTitle": "Validators",
|
|
1250
|
+
"dirName": "credit-card",
|
|
1251
|
+
"routePath": "credit-card",
|
|
1252
|
+
"importPath": "ngx-oneforall/validators/credit-card",
|
|
1253
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/credit-card",
|
|
1254
|
+
"description": "It enforces specific PAN lengths (13, 15, 16, 19) and validates 15-digit cards as American Express (must start with 34 or 37). It also handles non-numeric characters (separators) by stripping them before validation.",
|
|
1255
|
+
"fullContent": "`creditCard` is a validator that checks if the control's value is a valid credit card number using the Luhn algorithm.\n\nIt enforces specific PAN lengths (13, 15, 16, 19) and validates 15-digit cards as American Express (must start with 34 or 37). It also handles non-numeric characters (separators) by stripping them before validation.\n\n## Usage\n\nUse `creditCard` to validate credit card inputs.\n\n{{ NgDocActions.demo(\"CreditCardDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { creditCard } from 'ngx-oneforall/validators/credit-card';\n\nconst control = new FormControl(null, creditCard);\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `creditCard` attribute directive.\n\n```html\n<input type=\"text\" [(ngModel)]=\"value\" creditCard>\n```\n\n## API\n\n`creditCard: ValidatorFn`\n\nReturns a validation error object with a reason code if validation fails, or `null` if valid.\n\n### Error Codes\n\n| Reason | Description |\n|--------|-------------|\n| `repeated_digits` | All digits are identical (e.g., `0000000000000000`) |\n| `invalid_length` | PAN length is not 13, 15, 16, or 19 digits |\n| `invalid_amex_prefix` | 15-digit card doesn't start with 34 or 37 |\n| `luhn_failed` | Luhn algorithm checksum failed |\n\n```typescript\n// Example error object\n{ creditCard: { reason: 'luhn_failed' } }\n{ creditCard: { reason: 'invalid_length', actualLength: 12 } }\n```"
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
"name": "Date",
|
|
1259
|
+
"category": "validators",
|
|
1260
|
+
"categoryTitle": "Validators",
|
|
1261
|
+
"dirName": "date",
|
|
1262
|
+
"routePath": "date",
|
|
1263
|
+
"importPath": "ngx-oneforall/validators/date",
|
|
1264
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/date",
|
|
1265
|
+
"description": "Use date to validate date inputs.",
|
|
1266
|
+
"fullContent": "`date` is a validator that ensures the control's value is a valid date. It supports `Date` objects and date strings.\n\n## Usage\n\nUse `date` to validate date inputs.\n\n{{ NgDocActions.demo(\"DateDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { date } from 'ngx-oneforall/validators/date';\n\nconst control = new FormControl(null, date);\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `date` attribute directive (or `[date]`) with template-driven forms.\n\n```html\n<input type=\"text\" [(ngModel)]=\"value\" date>\n```\n\n## API\n\n`date: ValidatorFn`\n\nReturns a validation error object with a reason code if validation fails, or `null` if valid.\n\n### Error Codes\n\n| Reason | Description |\n|--------|-------------|\n| `invalid_date` | Value cannot be parsed as a valid date |\n| `unsupported_type` | Value is not a string or Date object |\n\n```typescript\n// Example error objects\n{ date: { reason: 'invalid_date', actualValue: 'not a date' } }\n{ date: { reason: 'unsupported_type', actualValue: true } }\n```"
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
"name": "Match Field",
|
|
1270
|
+
"category": "validators",
|
|
1271
|
+
"categoryTitle": "Validators",
|
|
1272
|
+
"dirName": "match-field",
|
|
1273
|
+
"routePath": "match-field",
|
|
1274
|
+
"importPath": "ngx-oneforall/validators/match-field",
|
|
1275
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/match-field",
|
|
1276
|
+
"description": "Applied at the FormGroup level so it detects changes to both fields:",
|
|
1277
|
+
"fullContent": "`matchFields` is a **group-level validator** that checks if two fields have matching values. Commonly used for \"confirm password\" or \"confirm email\" fields.\n\n{{ NgDocActions.demo(\"MatchFieldDemoComponent\", { container: true }) }}\n\n## Usage\n\nApplied at the **FormGroup level** so it detects changes to both fields:\n\n```typescript\nimport { FormGroup, FormControl, Validators } from '@angular/forms';\nimport { matchFields } from 'ngx-oneforall/validators/match-field';\n\nconst form = new FormGroup({\n password: new FormControl('', Validators.required),\n confirmPassword: new FormControl('', Validators.required)\n}, { validators: matchFields('password', 'confirmPassword') });\n```\n\n## API\n\n`matchFields(field1: string, field2: string): ValidatorFn`\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `field1` | `string` | Name of the first control to compare |\n| `field2` | `string` | Name of the second control to compare |\n\n### Error Object\n\nWhen validation fails, returns error on the **FormGroup** (not individual controls):\n```typescript\n{\n matchFields: {\n field1: 'password',\n field1Value: 'test123',\n field2: 'confirmPassword',\n field2Value: 'different'\n }\n}\n```\n\n## Template Example\n\n```html\n<form [formGroup]=\"form\">\n <input formControlName=\"password\" type=\"password\" placeholder=\"Password\">\n <input formControlName=\"confirmPassword\" type=\"password\" placeholder=\"Confirm Password\">\n \n @if (form.hasError('matchFields')) {\n <span class=\"error\">Passwords do not match</span>\n }\n</form>\n```\n\n## Template-Driven Forms (Directive)\n\nUse the `matchFields` directive with an array of field names:\n\n```html\n<form ngForm [matchFields]=\"['password', 'confirmPassword']\">\n <input type=\"password\" name=\"password\" ngModel />\n <input type=\"password\" name=\"confirmPassword\" ngModel />\n \n @if (form.hasError('matchFields')) {\n <span class=\"error\">Passwords do not match</span>\n }\n</form>\n```\n\n```typescript\nimport { MatchFieldsValidator } from 'ngx-oneforall/validators/match-field';\n\n@Component({\n imports: [FormsModule, MatchFieldsValidator],\n})\n```"
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
"name": "Max Date",
|
|
1281
|
+
"category": "validators",
|
|
1282
|
+
"categoryTitle": "Validators",
|
|
1283
|
+
"dirName": "max-date",
|
|
1284
|
+
"routePath": "max-date",
|
|
1285
|
+
"importPath": "ngx-oneforall/validators/max-date",
|
|
1286
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/max-date",
|
|
1287
|
+
"description": "Use maxDate to validate that a date is not after a certain boundary.",
|
|
1288
|
+
"fullContent": "`maxDate` is a validator that ensures the control's value is a date less than or equal to a specified maximum date.\n\n## Usage\n\nUse `maxDate` to validate that a date is not after a certain boundary.\n\n>**Note** This validator internally uses the `date` validator to first ensure the inputs are valid date structures.\n\n{{ NgDocActions.demo(\"MaxDateDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { maxDate } from 'ngx-oneforall/validators/max-date';\n\nconst control = new FormControl(null, maxDate(new Date('2025-12-31')));\n// OR with string\nconst control = new FormControl(null, maxDate('2025-12-31'));\n// OR with timestamp\nconst control = new FormControl(null, maxDate(1735689600000));\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[maxDate]` directive. It accepts a `Date` object, date string, or numeric timestamp.\n\n```html\n<input type=\"date\" [(ngModel)]=\"value\" [maxDate]=\"maxDateValue\">\n```\n\n## API\n\n`maxDate(max: Date | string | number): ValidatorFn`\n\nReturns `{ maxDate: { reason: 'date_exceeds_max', requiredDate, actualValue } }` if validation fails, or `null` if valid."
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
"name": "Min Date",
|
|
1292
|
+
"category": "validators",
|
|
1293
|
+
"categoryTitle": "Validators",
|
|
1294
|
+
"dirName": "min-date",
|
|
1295
|
+
"routePath": "min-date",
|
|
1296
|
+
"importPath": "ngx-oneforall/validators/min-date",
|
|
1297
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/min-date",
|
|
1298
|
+
"description": "Use minDate to validate that a date is not before a certain boundary.",
|
|
1299
|
+
"fullContent": "`minDate` is a validator that ensures the control's value is a date greater than or equal to a specified minimum date.\n\n## Usage\n\nUse `minDate` to validate that a date is not before a certain boundary.\n\n>**Note** This validator internally uses the `date` validator to first ensure the inputs are valid date structures.\n\n{{ NgDocActions.demo(\"MinDateDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { minDate } from 'ngx-oneforall/validators/min-date';\n\nconst control = new FormControl(null, minDate(new Date('2023-01-01')));\n// OR with string\nconst control = new FormControl(null, minDate('2023-01-01'));\n// OR with timestamp\nconst control = new FormControl(null, minDate(1672531200000));\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[minDate]` directive. It accepts a `Date` object, date string, or numeric timestamp.\n\n```html\n<input type=\"date\" [(ngModel)]=\"value\" [minDate]=\"minDateValue\">\n```\n\n## API\n\n`minDate(min: Date | string | number): ValidatorFn`\n\nReturns `{ minDate: { reason: 'date_before_min', requiredDate, actualValue } }` if validation fails, or `null` if valid."
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
"name": "Min Length Trimmed",
|
|
1303
|
+
"category": "validators",
|
|
1304
|
+
"categoryTitle": "Validators",
|
|
1305
|
+
"dirName": "min-length-trimmed",
|
|
1306
|
+
"routePath": "min-length-trimmed",
|
|
1307
|
+
"importPath": "ngx-oneforall/validators/min-length-trimmed",
|
|
1308
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/min-length-trimmed",
|
|
1309
|
+
"description": "Unlike Angular's built-in Validators.minLength, this validator trims the value first, preventing whitespace-only strings from passing validation.",
|
|
1310
|
+
"fullContent": "`minLengthTrimmed` is a validator that trims whitespace before checking minimum length.\n\n## Usage\n\nUnlike Angular's built-in `Validators.minLength`, this validator trims the value first, preventing whitespace-only strings from passing validation.\n\n{{ NgDocActions.demo(\"MinLengthTrimmedDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { minLengthTrimmed } from 'ngx-oneforall/validators/min-length-trimmed';\n\nconst control = new FormControl('', minLengthTrimmed(3));\n\ncontrol.setValue(' ab '); // invalid - trimmed length is 2\ncontrol.setValue('abc'); // valid - length is 3\n```\n\n### Template-Driven Forms (Directive)\n\n```html\n<input type=\"text\" [(ngModel)]=\"username\" [minLengthTrimmed]=\"3\">\n```\n\n## API\n\n`minLengthTrimmed(minLength: number): ValidatorFn`\n\n### Error Object\n\nWhen validation fails, returns:\n\n```typescript\n{\n minLengthTrimmed: {\n requiredLength: number,\n actualLength: number\n }\n}\n```\n\n### Behavior\n\n| Value | Min Length | Result |\n|-------|------------|--------|\n| `null` / `undefined` | any | Valid |\n| `'ab'` | 3 | Invalid (length: 2) |\n| `' ab '` | 3 | Invalid (trimmed length: 2) |\n| `'abc'` | 3 | Valid |\n| `' abc '` | 3 | Valid (trimmed length: 3) |\n| `' '` | 1 | Invalid (trimmed length: 0) |"
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
"name": "Not Blank",
|
|
1314
|
+
"category": "validators",
|
|
1315
|
+
"categoryTitle": "Validators",
|
|
1316
|
+
"dirName": "not-blank",
|
|
1317
|
+
"routePath": "not-blank",
|
|
1318
|
+
"importPath": "ngx-oneforall/validators/not-blank",
|
|
1319
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/not-blank",
|
|
1320
|
+
"description": "Use notBlank to validate that input values contain actual content, not just whitespace. Unlike Validators.required, this validator fails for strings containing only spaces, tabs, or newlines.",
|
|
1321
|
+
"fullContent": "`notBlank` is a validator that ensures the control's value is not blank (empty or whitespace-only).\n\n## Usage\n\nUse `notBlank` to validate that input values contain actual content, not just whitespace. Unlike `Validators.required`, this validator fails for strings containing only spaces, tabs, or newlines.\n\n{{ NgDocActions.demo(\"NotBlankDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl, Validators } from '@angular/forms';\nimport { notBlank } from 'ngx-oneforall/validators/not-blank';\n\n// Use alone - allows null/undefined\nconst control = new FormControl(null, notBlank);\n\n// Combine with required for mandatory non-blank field\nconst requiredControl = new FormControl(null, [Validators.required, notBlank]);\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[notBlank]` directive with template-driven forms.\n\n```html\n<input type=\"text\" [(ngModel)]=\"name\" notBlank>\n```\n\n## API\n\n`notBlank: ValidatorFn`\n\n>**Note** Unlike other validators that are functions, `notBlank` is a pre-created `ValidatorFn` constant since it requires no configuration.\n\n### Error Object\n\nWhen validation fails, returns:\n\n```typescript\n{ notBlank: true }\n```\n\n### Behavior\n\n| Value | Result |\n|-------|--------|\n| `null` / `undefined` | Valid (allows composition with `required`) |\n| `''` (empty string) | Invalid |\n| `' '` (whitespace only) | Invalid |\n| `'\\t\\n'` (tabs/newlines) | Invalid |\n| `'hello'` | Valid |\n| `' hello '` | Valid |\n| Non-string values | Valid |"
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
"name": "Number",
|
|
1325
|
+
"category": "validators",
|
|
1326
|
+
"categoryTitle": "Validators",
|
|
1327
|
+
"dirName": "number",
|
|
1328
|
+
"routePath": "number",
|
|
1329
|
+
"importPath": "ngx-oneforall/validators/number",
|
|
1330
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/number",
|
|
1331
|
+
"description": "Use number to validate that input values are strictly numeric.",
|
|
1332
|
+
"fullContent": "`number` is a validator that ensures the control's value is a valid finite number or a string representation of a valid finite number.\n\n## Usage\n\nUse `number` to validate that input values are strictly numeric.\n\n{{ NgDocActions.demo(\"NumberDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { number } from 'ngx-oneforall/validators/number';\n\nconst control = new FormControl(null, number);\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `number` attribute directive (or `[number]`) with template-driven forms.\n\n```html\n<input type=\"text\" [(ngModel)]=\"value\" number>\n```\n\n## API\n\n`number: ValidatorFn`\n\nReturns a validation error object `{ number: { actualValue } }` if validation fails, or `null` if valid."
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"name": "Phone",
|
|
1336
|
+
"category": "validators",
|
|
1337
|
+
"categoryTitle": "Validators",
|
|
1338
|
+
"dirName": "phone",
|
|
1339
|
+
"routePath": "phone",
|
|
1340
|
+
"importPath": "ngx-oneforall/validators/phone",
|
|
1341
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/phone",
|
|
1342
|
+
"description": "It uses libphonenumber-js under the hood to validate phone numbers.",
|
|
1343
|
+
"fullContent": "`phone` is a validator that checks if the control's value is a valid phone number for a specified country code.\n\nIt uses `libphonenumber-js` under the hood to validate phone numbers.\n\n> **Warning** This validator depends on `libphonenumber-js`, which is 145kb in size. Using this validator will increase your bundle size. Proceed with caution if bundle size is a critical constraint.\n\n## Usage\n\nUse `phone` to validate phone numbers. You must provide a `CountryCode` (Alpha-2 code).\n\n{{ NgDocActions.demo(\"PhoneDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { phoneValidator } from 'ngx-oneforall/validators/phone';\nimport { CountryCode } from 'ngx-oneforall/constants';\n\nconst control = new FormControl(null, phoneValidator(CountryCode.UnitedStates));\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[phone]` attribute directive.\n\n```html\n<input type=\"text\" [(ngModel)]=\"value\" [phone]=\"'US'\">\n<!-- Or use the CountryCode enum -->\n<input type=\"text\" [(ngModel)]=\"value\" [phone]=\"CountryCode.UnitedStates\">\n```\n\n## API\n\n`phoneValidator(country: CountryCode): ValidatorFn`\n\nReturns `{ phone: { reason: 'invalid_format', country } }` if validation fails, or `null` if valid."
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
"name": "Range",
|
|
1347
|
+
"category": "validators",
|
|
1348
|
+
"categoryTitle": "Validators",
|
|
1349
|
+
"dirName": "range",
|
|
1350
|
+
"routePath": "range",
|
|
1351
|
+
"importPath": "ngx-oneforall/validators/range",
|
|
1352
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/range",
|
|
1353
|
+
"description": "Use range to validate numeric inputs against a minimum and maximum value.",
|
|
1354
|
+
"fullContent": "`range` is a validator that requires the control's value to be within a specified numerical range (inclusive).\n\n## Usage\n\nUse `range` to validate numeric inputs against a minimum and maximum value.\n\n{{ NgDocActions.demo(\"RangeDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { range } from 'ngx-oneforall/validators/range';\n\nconst control = new FormControl(null, range(5, 10));\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[range]` directive with template-driven forms. It accepts a tuple `[min, max]`.\n\n```html\n<input type=\"number\" [(ngModel)]=\"value\" [range]=\"[5, 10]\">\n```\n\n## API\n\n`range(min: number, max: number): ValidatorFn`\n\n- **min**: The minimum required value.\n- **max**: The maximum required value.\n\nReturns `{ range: { reason: 'out_of_range', min, max, actualValue } }` if validation fails, or `null` if valid."
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
"name": "Range Length",
|
|
1358
|
+
"category": "validators",
|
|
1359
|
+
"categoryTitle": "Validators",
|
|
1360
|
+
"dirName": "range-length",
|
|
1361
|
+
"routePath": "range-length",
|
|
1362
|
+
"importPath": "ngx-oneforall/validators/range-length",
|
|
1363
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/range-length",
|
|
1364
|
+
"description": "Use rangeLength to validate form controls where the input size matters, such as usernames, passwords, or list selections.",
|
|
1365
|
+
"fullContent": "`rangeLength` is a validator that requires the length of the value (string, array, or number digits) to be within a specified range.\n\n## Usage\n\nUse `rangeLength` to validate form controls where the input size matters, such as usernames, passwords, or list selections.\n\n{{ NgDocActions.demo(\"RangeLengthDemoComponent\", { container: true }) }}\n\n### Example\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { rangeLength } from 'ngx-oneforall/validators/range-length';\n\nconst control = new FormControl('', rangeLength(5, 10));\n```\n\n### Directive Usage\n\nYou can also use `[rangeLength]` directive with template-driven forms:\n\n```html\n<input [(ngModel)]=\"value\" [rangeLength]=\"[5, 10]\">\n```\n\n## API\n\n`rangeLength(min: number, max: number): ValidatorFn`\n\n- **min**: Minimum required length.\n- **max**: Maximum allowed length.\n\nReturns `{ rangeLength: { reason: 'length_out_of_range', requiredMinLength, requiredMaxLength, actualLength } }` if validation fails, or `null` if valid.\n\nThrows an error if `min` is greater than `max`."
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
"name": "Url",
|
|
1369
|
+
"category": "validators",
|
|
1370
|
+
"categoryTitle": "Validators",
|
|
1371
|
+
"dirName": "url",
|
|
1372
|
+
"routePath": "url",
|
|
1373
|
+
"importPath": "ngx-oneforall/validators/url",
|
|
1374
|
+
"url": "https://love1024.github.io/ngx-oneforall/validators/url",
|
|
1375
|
+
"description": "Use url to validate that input values are valid URLs. It supports configuration for restricting protocols.",
|
|
1376
|
+
"fullContent": "`url` is a validator that ensures the control's value is a valid absolute URL string.\n\n## Usage\n\nUse `url` to validate that input values are valid URLs. It supports configuration for restricting protocols.\n\n{{ NgDocActions.demo(\"UrlDemoComponent\", { container: true }) }}\n\n### Reactive Forms\n\n```typescript\nimport { FormControl } from '@angular/forms';\nimport { url } from 'ngx-oneforall/validators/url';\n\nconst control = new FormControl(null, url({ protocols: ['https'] }));\n```\n\n### Template-Driven Forms (Directive)\n\nYou can use the `[url]` directive with template-driven forms. It accepts a `UrlValidatorOptions` object.\n\n```html\n<input type=\"text\" [(ngModel)]=\"value\" [url]=\"{ protocols: ['https'] }\">\n```\n\n## API\n\n`url(options: UrlValidatorOptions): ValidatorFn`\n\nOptions:\n- `protocols?: readonly string[]`: List of allowed protocols (e.g., `['https', 'ftp']`). Only checked for absolute URLs.\n- `skipProtocol?: boolean`: If `true`, allows URLs without a protocol scheme (e.g., `google.com`). Default `false`.\n\n### Error Codes\n\n| Reason | Description |\n|--------|-------------|\n| `invalid_format` | Value is not a valid URL |\n| `invalid_protocol` | Protocol does not match allowed list |\n| `unsupported_type` | Value is not a string |"
|
|
1377
|
+
}
|
|
1378
|
+
]
|
|
1379
|
+
}
|