@hichchi/ngx-utils
v0.0.9
Published
A utility library for Angular applications with HTTP interceptors, authentication services, and state management
Readme
📦 Installation
npm install @hichchi/ngx-utils🌟 Overview
This library provides a collection of utilities for Angular applications, including HTTP interceptors, authentication services, state management, and form utilities. It helps streamline common tasks in Angular development and promotes consistent implementation patterns.
✨ Key Features
- 🌐 HTTP Interceptors: Pre-configured interceptors for API URLs, authentication, error handling, and response transformation
- 🔐 Authentication Services: Services for handling user authentication and authorization
- 📊 State Management: State management utilities for authentication and other application states
- 📝 Form Utilities: Helper functions for working with Angular forms
- 📋 Interface Definitions: TypeScript interfaces for consistent typing
- 🛠️ Common Services: Reusable services for Angular applications
🚀 Usage
HTTP Interceptors
import { NgModule } from "@angular/core";
import { HTTP_INTERCEPTORS } from "@angular/common/http";
import {
apiInterceptor,
AuthInterceptor,
ErrorInterceptor,
ResponseInterceptor,
} from "@hichchi/ngx-utils/interceptors";
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: apiInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ResponseInterceptor, multi: true },
],
})
export class AppModule {}Authentication Service
import { Component } from "@angular/core";
import { AuthService } from "@hichchi/ngx-utils/services";
@Component({
selector: "app-sign-in",
template: `
<form (submit)="signIn()">
<input [(ngModel)]="username" name="username" placeholder="Username" />
<input
[(ngModel)]="password"
name="password"
type="password"
placeholder="Password"
/>
<button type="submit">Sign In</button>
</form>
`,
})
export class SignInComponent {
username = "";
password = "";
constructor(private authService: AuthService) {}
signIn() {
this.authService
.signIn({
email: this.username,
password: this.password,
})
.subscribe(
(response) => console.log("Sign in successful", response),
(error) => console.error("Sign in failed", error),
);
}
}State Management
import { Component, OnInit } from "@angular/core";
import { AuthState } from "@hichchi/ngx-auth/state";
@Component({
selector: "app-header",
template: `
<nav>
<a routerLink="/">Home</a>
<a *ngIf="isLoggedIn" routerLink="/profile">Profile</a>
<button *ngIf="isLoggedIn" (click)="signOut()">Sign Out</button>
<a *ngIf="!isLoggedIn" routerLink="/sign-in">Sign In</a>
</nav>
`,
})
export class HeaderComponent implements OnInit {
isLoggedIn = false;
constructor(private authState: AuthState) {}
ngOnInit() {
this.isLoggedIn = this.authState.signedIn();
}
signOut() {
this.authState.signOut();
}
}🔧 Development
Building
nx build ngx-utilsRunning unit tests
nx test ngx-utilsTests are executed via Jest.
Made with ❤️ by Hichchi Dev
Building the future of Angular development, one commit at a time
📖 API Documentation
Complete technical reference for all classes, interfaces, methods, and types in this library.
Auto-generated by TypeDoc - Browse through detailed API references, code examples, and implementation guides below.
📋 API Table of Contents
Classes
abstract CrudHttpService
Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:20
Type Parameters
Mdl extends Model
Model
Constructors
Constructor
new CrudHttpService<Mdl>(): CrudHttpService<Mdl>;Returns
CrudHttpService<Mdl>
Methods
delete()
Call Signature
delete<Res>(url, options?): Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:95
Type Parameters
Res
unknown
Parameters
url
string | string[]
options?
Returns
Observable<Res>
Call Signature
delete<Res>(url, options?): Promise<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:97
Type Parameters
Res
unknown
Parameters
url
string | string[]
options?
Returns
Promise<Res>
get()
Call Signature
get<Res>(url, options?): Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:48
Type Parameters
Res
unknown
Parameters
url
string | string[]
options?
HttpGetOptions<Mdl>
Returns
Observable<Res>
Call Signature
get<Res>(url, options?): Promise<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:50
Type Parameters
Res
unknown
Parameters
url
string | string[]
options?
Returns
Promise<Res>
patch()
Call Signature
patch<Res, B>(
url,
body,
options?): Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:83
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Observable<Res>
Call Signature
patch<Res, B>(
url,
body,
options?): Promise<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:85
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Promise<Res>
post()
Call Signature
post<Res, B>(
url,
body,
options?): Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:59
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Observable<Res>
Call Signature
post<Res, B>(
url,
body,
options?): Promise<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:61
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Promise<Res>
put()
Call Signature
put<Res, B>(
url,
body,
options?): Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:71
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Observable<Res>
Call Signature
put<Res, B>(
url,
body,
options?): Promise<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:73
Type Parameters
Res
unknown
B
unknown
Parameters
url
string | string[]
body
B
options?
Returns
Promise<Res>
request()
protected request<Res, Body>(
type,
url,
body,
options?): Promise<Res> | Observable<Res>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:23
Type Parameters
Res
unknown
Body
unknown
Parameters
type
RequestType
url
string | string[]
body
Body
options?
| HttpGetOptions<Mdl> | HttpGetOptionsPromise<Mdl>
Returns
Promise<Res> | Observable<Res>
parseQuery()
static parseQuery<T>(options?): HttpQuery<Model>;Defined in: libs/ngx-utils/src/lib/services/crud-http.service.ts:106
Type Parameters
T
Parameters
options?
| HttpGetOptions<T> | HttpGetOptionsPromise<T>
Returns
HttpQuery<Model>
Properties
http
protected
HttpClient
libs/ngx-utils/src/lib/services/crud-http.service.ts:21
Functions
apiInterceptor()
function apiInterceptor(apiBase, splitDomain?, tenant?): HttpInterceptorFn;Defined in: libs/ngx-utils/src/lib/interceptors/api.interceptor.ts:87
Creates an HTTP interceptor that rewrites relative request URLs using a base API host and optionally attaches a tenant header for multi-tenant applications.
This interceptor allows Angular applications to:
- Use relative request URLs in services and components
- Automatically prepend a base API URL for consistency
- Add a tenant identifier via a custom HTTP header (
x-tenant) if provided or extracted from the current origin usingsplitDomain
How the interceptor works:
- Requests that already start with the provided
apiBaseor withhttp://orhttps://are passed through unchanged - All other relative requests are rewritten as:
${apiBase}/${req.url} - If a
tenantstring is provided or a subdomain is extracted usingsplitDomain, it is added to the request headers using theTENANT_HEADER_KEYconstant
Parameters
apiBase
string
The base API URL used to build relative request URLs (e.g., "https://api.example.com")
splitDomain?
string
Optional domain name used to extract subdomain from the current URL (e.g., "example.com")
tenant?
TenantSlug
Optional tenant identifier to attach via header (e.g., "tenant-a")
Returns
HttpInterceptorFn
An HttpInterceptorFn that can be registered with Angular's HttpClient
Examples
// Basic usage in app configuration
apiInterceptor("https://api.example.com");// Using environment configuration
apiInterceptor(environment.apiUrl);// With a static tenant
apiInterceptor("https://api.example.com", undefined, "tenant-a");
// Relative request 'users' -> 'https://api.example.com/users'
// Header 'x-tenant: tenant-a' is attached to the request// Using splitDomain to automatically extract tenant from URL
// Current page URL: https://tenant123.example.com
apiInterceptor("https://api.example.com", "example.com");
// Relative request 'users' -> 'https://api.example.com/users'
// Header 'x-tenant: tenant123' is attached to the request// In a service using relative URLs
@Injectable()
export class UserService {
constructor(private http: HttpClient) {}
getUsers() {
// Relative URL becomes: https://api.example.com/users
// Tenant header is added if specified or extracted
return this.http.get("users");
}
getUserById(id: string) {
return this.http.get(`users/${id}`);
}
// Absolute URLs are passed through unchanged
getExternalData() {
return this.http.get("https://external-api.com/data");
}
}See
- HttpInterceptorFn Angular HTTP interceptor function type
- HttpRequest Angular HTTP request interface
- HEADER_TENANT_KEY Constant used to attach tenant header
- extractSubdomain Utility function for extracting subdomains from URLs
createFormData()
function createFormData<T>(data): FormData;Defined in: libs/ngx-utils/src/lib/form/form.utils.ts:404
Creates a FormData object from a plain JavaScript object
This utility function converts a plain object into a FormData object, which is required for multipart/form-data HTTP requests, particularly when uploading files or sending form data that includes binary content. The function handles different data types appropriately, preserving file names for File objects and converting other values to strings.
The function is particularly useful when working with Angular forms that need to submit both regular form fields and file uploads in a single request. It automatically handles the conversion of various data types to the format expected by FormData.
Key features:
- Preserves original file names for File objects
- Converts primitive values to strings
- Maintains type safety with generic constraints
- Handles Blob objects correctly
- Creates multipart/form-data compatible output
Type Parameters
T extends object
Object type with string keys and values that can be converted to FormData
Parameters
data
T
Object containing the data to convert to FormData
Returns
FormData
A FormData object ready for HTTP submission
Examples
// Basic usage with mixed data types
const formData = createFormData({
name: "John Doe",
age: 30,
isActive: true,
avatar: fileInput.files[0], // File object
});
// Submit via HTTP
this.http.post("/api/users", formData).subscribe();// File upload with metadata
export class FileUploadComponent {
onFileUpload(file: File, description: string, isPublic: boolean) {
const uploadData = createFormData({
file: file,
description: description,
isPublic: isPublic,
uploadedAt: new Date().toISOString(),
});
this.fileService.upload(uploadData).subscribe({
next: (response) => console.log("Upload successful"),
error: (error) => console.error("Upload failed", error),
});
}
}// Using with form validation
export class ProfileFormComponent {
profileForm = this.fb.group({
name: ["", Validators.required],
bio: [""],
profilePicture: [null],
});
onSubmit() {
const formValue = validatedFormData(this.profileForm);
if (!formValue) return;
// Convert to FormData for file upload
const formData = createFormData({
name: formValue.name,
bio: formValue.bio || "",
profilePicture: formValue.profilePicture,
timestamp: Date.now(),
});
this.profileService.updateProfile(formData);
}
}// Multiple file upload
interface UploadRequest {
title: string;
category: string;
document: File;
thumbnail: File;
isPrivate: boolean;
}
const uploadRequest: UploadRequest = {
title: "My Document",
category: "reports",
document: documentFile,
thumbnail: thumbnailFile,
isPrivate: false,
};
const formData = createFormData(uploadRequest);
// FormData will contain:
// - title: "My Document"
// - category: "reports"
// - document: [File object with original name]
// - thumbnail: [File object with original name]
// - isPrivate: "false"See
- FormData Web API interface for form data
- File Web API interface for file objects
- Blob Web API interface for binary data
- validatedFormData Function for getting validated form data to use with this utility
errorResponseInterceptor()
function errorResponseInterceptor(
providerWithNotify,
providerWithSignOut,
): HttpInterceptorFn;Defined in: libs/ngx-utils/src/lib/interceptors/error.interceptor.ts:140
Creates an HTTP error response interceptor for Angular applications
This function creates an HTTP interceptor that handles error responses from API calls. It provides centralized error handling with support for authentication error detection, automatic user sign-out on unauthorized access, and configurable error notifications. The interceptor integrates with notification services and authentication services to provide a seamless error handling experience.
The interceptor distinguishes between different types of errors and handles them appropriately. It can detect known authentication errors, handle unauthorized access by automatically signing out users, and show error notifications based on request context configuration.
Key features:
- Centralized HTTP error handling for all API requests
- Authentication error detection and handling
- Automatic user sign-out on unauthorized access
- Configurable error notifications per request
- Integration with notification and authentication services
- Support for both client-side and server-side errors
- Context-aware error handling based on request configuration
Parameters
providerWithNotify
Type<{ error: (message) => void; }>
Service provider type that implements error notification functionality
providerWithSignOut
Type<{ signOut: () => Observable<any>; }>
Service provider type that implements user sign-out functionality
Returns
HttpInterceptorFn
HttpInterceptorFn that can be used in Angular HTTP interceptor configuration
Examples
// Basic usage in app configuration
import { provideHttpClient, withInterceptors } from "@angular/common/http";
import { NotificationService } from "./services/notification.service";
import { AuthService } from "./services/auth.service";
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
errorResponseInterceptor(NotificationService, AuthService),
]),
),
],
};// Using with custom notification and auth services
import { ToastService } from "./services/toast.service";
import { UserAuthService } from "./services/user-auth.service";
const errorInterceptor = errorResponseInterceptor(
ToastService,
UserAuthService,
);
export const appConfig: ApplicationConfig = {
providers: [provideHttpClient(withInterceptors([errorInterceptor]))],
};// Service implementations that work with the interceptor
@Injectable()
export class NotificationService {
error(message: string): void {
// Show error notification to user
this.toastr.error(message);
}
}
@Injectable()
export class AuthService {
signOut(): void {
// Clear user session and redirect to login
this.clearTokens();
this.router.navigate(["/login"]);
}
}// Making HTTP requests with error notification control
import { HttpClient } from "@angular/common/http";
import { skipNotifyContext } from "@hichchi/ngx-utils";
@Injectable()
export class DataService {
constructor(private http: HttpClient) {}
// Request with error notifications enabled (default)
getData() {
return this.http.get("/api/data");
}
// Request with error notifications disabled
getDataSilently() {
return this.http.get("/api/data", skipNotifyContext(true));
}
}// Advanced usage with multiple interceptors
import { AuthInterceptor } from "./interceptors/auth.interceptor";
import { LoadingInterceptor } from "./interceptors/loading.interceptor";
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
AuthInterceptor,
LoadingInterceptor,
errorResponseInterceptor(NotificationService, AuthService),
]),
),
],
};See
- HttpInterceptorFn Angular HTTP interceptor function type
- HttpError Interface for HTTP error objects
- NOTIFY_ERRORS Token for controlling error notification context
- AuthErrorResponseCode Enum of known authentication error codes
- HttpClientErrorStatus Enum of HTTP client error status codes
extractSubdomain()
function extractSubdomain(splitDomain?): string | undefined;Defined in: libs/ngx-utils/src/lib/utils/http.utils.ts:69
Extract a subdomain from the current origin URL
This utility function parses the current page's URL (window.location.href)
and extracts the subdomain portion relative to the provided main domain.
Behavior:
- Returns the subdomain if the hostname contains one before the
splitDomain - Returns
undefinedfor single-label hostnames (e.g.,localhost), IP addresses, or if no subdomain exists
Parameters
splitDomain?
string
The main domain used as reference for extraction (e.g., "example.com")
Returns
string | undefined
The extracted subdomain if found, or undefined otherwise
Examples
extractSubdomain("example.com");
// On "admin.example.com" -> returns "admin"extractSubdomain("example.com");
// On "localhost:3000" -> returns undefinedextractSubdomain("example.com");
// On "example.com" -> returns undefined (no subdomain)getClosestScrollableElement()
function getClosestScrollableElement(el): HTMLElement | null;Defined in: libs/ngx-utils/src/lib/utils/html.utils.ts:257
Finds the closest scrollable ancestor element in the DOM tree
This utility function traverses up the DOM tree from a given element to find the nearest ancestor that is scrollable. It uses the isScrollable function to determine scrollability and returns the first scrollable parent element found.
This is useful for implementing scroll-related functionality that needs to work with the appropriate scrollable container, such as:
- Implementing custom scroll behaviors
- Adding scroll event listeners to the correct container
- Calculating scroll positions relative to the scrollable parent
- Implementing scroll-to-element functionality
Parameters
el
HTMLElement
The starting HTML element to search from
Returns
HTMLElement | null
The closest scrollable ancestor element, or null if none is found
Examples
// Find the scrollable container for a specific element
const targetElement = document.querySelector(".target-element");
if (targetElement) {
const scrollableParent = getClosestScrollableElement(targetElement);
if (scrollableParent) {
console.log("Found scrollable parent:", scrollableParent);
// Add scroll event listener to the correct container
scrollableParent.addEventListener("scroll", handleScroll);
} else {
console.log("No scrollable parent found");
}
}// Implement scroll-to-element functionality
function scrollToElement(
element: HTMLElement,
behavior: ScrollBehavior = "smooth",
) {
const scrollableContainer = getClosestScrollableElement(element);
if (scrollableContainer) {
// Calculate the position relative to the scrollable container
const containerRect = scrollableContainer.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
const relativeTop =
elementRect.top - containerRect.top + scrollableContainer.scrollTop;
scrollableContainer.scrollTo({
top: relativeTop,
behavior,
});
} else {
// Fallback to window scroll
element.scrollIntoView({ behavior });
}
}// Use in Angular directive for scroll-based functionality
@Directive({
selector: "[appScrollSpy]",
})
export class ScrollSpyDirective implements OnInit, OnDestroy {
private scrollContainer: HTMLElement | null = null;
private scrollListener?: () => void;
constructor(private elementRef: ElementRef<HTMLElement>) {}
ngOnInit() {
this.scrollContainer = getClosestScrollableElement(
this.elementRef.nativeElement,
);
if (this.scrollContainer) {
this.scrollListener = () => this.onScroll();
this.scrollContainer.addEventListener("scroll", this.scrollListener);
}
}
ngOnDestroy() {
if (this.scrollContainer && this.scrollListener) {
this.scrollContainer.removeEventListener("scroll", this.scrollListener);
}
}
private onScroll() {
// Implement scroll spy logic
if (
this.scrollContainer &&
isElementInView(this.elementRef.nativeElement, this.scrollContainer)
) {
// Element is in view
console.log("Element is visible in scroll container");
}
}
}See
- isScrollable Function used internally to determine scrollability
- isElementInView Function that can be used with the returned scrollable element
- HTMLElement.parentElement DOM property used for tree traversal
isElementInView()
function isElementInView(el, container, threshold?): boolean;Defined in: libs/ngx-utils/src/lib/utils/html.utils.ts:153
Determines if an element is fully visible within a container element
This utility function checks whether a target element is completely visible within the bounds of a container element. It compares the bounding rectangles of both elements and optionally applies a threshold for more flexible visibility detection.
This is particularly useful for implementing features like:
- Lazy loading of content when elements come into view
- Scroll-based animations and transitions
- Virtual scrolling implementations
- Accessibility features that track visible content
Parameters
el
HTMLElement
undefined
The target element to check for visibility
container
HTMLElement
undefined
The container element that defines the visible area
threshold
number
0
Optional threshold in pixels for more flexible visibility detection (default: 0)
Returns
boolean
True if the element is fully visible within the container, false otherwise
Examples
// Check if a list item is visible in a scrollable container
const listItem = document.querySelector(".list-item");
const scrollContainer = document.querySelector(".scroll-container");
if (listItem && scrollContainer && isElementInView(listItem, scrollContainer)) {
console.log("List item is fully visible");
// Trigger animations or load additional content
}// Use with a threshold for partial visibility detection
const image = document.querySelector(".lazy-image");
const viewport = document.querySelector(".viewport");
// Check if image is visible with 50px threshold
if (image && viewport && isElementInView(image, viewport, 50)) {
// Load the image when it's within 50px of being visible
loadImage(image);
}// Implement scroll-based visibility tracking in Angular
@Component({
selector: "app-scroll-tracker",
template: `
<div #container class="scroll-container" (scroll)="onScroll()">
<div
#item
*ngFor="let item of items; trackBy: trackByFn"
class="scroll-item"
[class.visible]="item.isVisible"
>
{{ item.content }}
</div>
</div>
`,
})
export class ScrollTrackerComponent {
@ViewChild("container") container!: ElementRef<HTMLElement>;
@ViewChildren("item") itemElements!: QueryList<ElementRef<HTMLElement>>;
items = [
{ id: 1, content: "Item 1", isVisible: false },
{ id: 2, content: "Item 2", isVisible: false },
// ... more items
];
onScroll() {
this.itemElements.forEach((itemRef, index) => {
this.items[index].isVisible = isElementInView(
itemRef.nativeElement,
this.container.nativeElement,
20, // 20px threshold
);
});
}
}See
- isScrollable Function to check if an element is scrollable
- getClosestScrollableElement Function to find the nearest scrollable ancestor
- getBoundingClientRect DOM method used internally for position calculation
isScrollable()
function isScrollable(el): boolean;Defined in: libs/ngx-utils/src/lib/utils/html.utils.ts:64
Determines if an HTML element is scrollable
This utility function checks whether an HTML element has scrollable content by examining its computed CSS overflow-y property and comparing its scroll height to its client height. An element is considered scrollable if it has overflow set to 'scroll' or 'auto' and its content exceeds the visible area.
This is useful for implementing scroll-related functionality, such as infinite scrolling, scroll position tracking, or determining whether scroll indicators should be shown.
Parameters
el
HTMLElement
The HTML element to check for scrollability
Returns
boolean
True if the element is scrollable, false otherwise
Examples
// Check if a container element is scrollable
const container = document.getElementById("content-container");
if (container && isScrollable(container)) {
console.log("Container has scrollable content");
// Add scroll event listeners or show scroll indicators
}// Use in a component to conditionally show scroll indicators
@Component({
selector: "app-scrollable-content",
template: `
<div #contentContainer class="content">
<!-- content -->
</div>
<div *ngIf="showScrollIndicator" class="scroll-indicator">
Scroll for more content
</div>
`,
})
export class ScrollableContentComponent implements AfterViewInit {
@ViewChild("contentContainer") contentContainer!: ElementRef<HTMLElement>;
showScrollIndicator = false;
ngAfterViewInit() {
this.showScrollIndicator = isScrollable(
this.contentContainer.nativeElement,
);
}
}// Check multiple elements for scrollability
const elements = document.querySelectorAll(".potential-scroll-container");
const scrollableElements = Array.from(elements).filter((el) =>
isScrollable(el as HTMLElement),
);
console.log(`Found ${scrollableElements.length} scrollable elements`);See
- getClosestScrollableElement Function to find the nearest scrollable ancestor
- isElementInView Function to check if an element is visible within a container
isSuccessResponse()
function isSuccessResponse(body): body is SuccessResponse;Defined in: libs/ngx-utils/src/lib/utils/http.utils.ts:17
Parameters
body
unknown
Returns
body is SuccessResponse
markFormDirty()
function markFormDirty(form): void;Defined in: libs/ngx-utils/src/lib/form/form.utils.ts:75
Recursively marks invalid form controls as dirty and touched
This utility function traverses a form hierarchy and marks all invalid controls as dirty and touched, which triggers validation error display in the UI. It works recursively through nested FormGroups and FormArrays to ensure all invalid controls are properly marked for error display.
The function is particularly useful when you want to show all validation errors at once, such as when a user attempts to submit a form. It only marks invalid controls, leaving valid controls unchanged.
Key features:
- Recursive traversal of form hierarchy
- Only marks invalid controls as dirty/touched
- Handles nested FormGroups and FormArrays
- Updates validation state after marking controls
- Non-destructive (doesn't affect valid controls)
Parameters
form
FormGroup
The FormGroup to process recursively
Returns
void
Examples
// Mark all invalid controls in a form for error display
export class UserFormComponent {
userForm = this.fb.group({
name: ["", Validators.required],
email: ["", [Validators.required, Validators.email]],
address: this.fb.group({
street: ["", Validators.required],
city: ["", Validators.required],
}),
});
onSubmit() {
if (this.userForm.invalid) {
// Mark all invalid fields to show errors
markFormDirty(this.userForm);
return;
}
// Process valid form...
}
}// Using with form arrays
export class DynamicFormComponent {
form = this.fb.group({
items: this.fb.array([
this.fb.group({
name: ["", Validators.required],
quantity: [0, Validators.min(1)],
}),
]),
});
validateAll() {
markFormDirty(this.form);
// All invalid controls in the array will be marked
}
}See
- FormGroup Angular reactive form group
- FormArray Angular reactive form array
- validatedFormData Function that uses this utility for validation
replaceNulls()
function replaceNulls<T>(obj): { [K in string | number | symbol]?: T[K] };Defined in: libs/ngx-utils/src/lib/form/form.utils.ts:166
Removes null values from an object by deleting properties with null values
This utility function creates a new object with all null properties removed. It's particularly useful when working with form data where null values should be omitted from API requests or when preparing data for processing that doesn't handle null values well.
The function performs a shallow copy of the object and removes any properties that have null values. Properties with undefined values are preserved, as they represent different semantic meaning (missing vs explicitly null).
Type Parameters
T
The type of the object being processed
Parameters
obj
{ [K in string | number | symbol]?: T[K] | null }
Object that may contain null values to be removed
Returns
{ [K in string | number | symbol]?: T[K] }
A new object with null properties removed
Examples
// Remove null values from form data
const formData = {
name: "John Doe",
email: "[email protected]",
phone: null,
address: null,
age: 30,
};
const cleanData = replaceNulls(formData);
// Result: { name: 'John Doe', email: '[email protected]', age: 30 }// Using with API request data
interface UserUpdate {
name?: string | null;
email?: string | null;
phone?: string | null;
}
const updateData: UserUpdate = {
name: "Jane Smith",
email: null, // Don't update email
phone: "555-1234",
};
const apiPayload = replaceNulls(updateData);
// Result: { name: 'Jane Smith', phone: '555-1234' }
// API receives only the fields to update// Difference between null and undefined
const data = {
field1: "value",
field2: null, // Will be removed
field3: undefined, // Will be preserved
};
const result = replaceNulls(data);
// Result: { field1: 'value', field3: undefined }See
validatedFormData Function that uses this utility to clean form data
saveAsFile()
function saveAsFile(blob, filename): void;Defined in: libs/ngx-utils/src/lib/utils/file.utils.ts:36
Save a Blob as a file by triggering a download in the browser. This function creates a temporary download link and triggers a click event to download the file.
Parameters
blob
Blob
Blob to save.
filename
string
File name with extension.
Returns
void
Throws
Throws an error if used in a Node.js environment.
Examples
// Save a text file
const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' });
saveAsFile(textBlob, 'hello.txt');// Save a JSON file
const data = { name: 'John', age: 30 };
const jsonBlob = new Blob([JSON.stringify(data)], { type: 'application/json' });
saveAsFile(jsonBlob, 'user.json');// Save a file from an API response
fetch('https://example.com/api/document')
.then(response => response.blob())
.then(blob => {
saveAsFile(blob, 'document.pdf');
});skipNotify()
function skipNotify(value?): HttpContext;Defined in: libs/ngx-utils/src/lib/utils/http.utils.ts:9
Parameters
value
boolean
false
Returns
HttpContext
skipNotifyContext()
function skipNotifyContext(value?): object;Defined in: libs/ngx-utils/src/lib/utils/http.utils.ts:13
Parameters
value
boolean
false
Returns
object
context
HttpContext
libs/ngx-utils/src/lib/utils/http.utils.ts:13
validatedFormData()
function validatedFormData<T>(
form,
): { [K in string | number | symbol]: T[K] } | null;Defined in: libs/ngx-utils/src/lib/form/form.utils.ts:278
Validates a form and returns clean data if valid, or null if invalid
This utility function combines form validation with data cleaning in a single operation. It first marks all invalid controls as dirty (to show validation errors), then checks if the form is valid. If valid, it returns the form data with null values removed. If invalid, it returns null.
This is particularly useful for form submission handlers where you want to:
- Show all validation errors if the form is invalid
- Get clean, validated data if the form is valid
- Handle both cases with a simple null check
The function uses the DataFormGroup type to ensure type safety between the form structure and the returned data type.
Type Parameters
T
The type of the data structure represented by the form
Parameters
form
The DataFormGroup to validate and extract data from
Returns
{ [K in string | number | symbol]: T[K] } | null
The validated and cleaned form data, or null if the form is invalid
Examples
// Basic form validation and submission
export class UserFormComponent {
userForm: DataFormGroup<UserData> = this.fb.group({
name: ["", Validators.required],
email: ["", [Validators.required, Validators.email]],
phone: [null], // Optional field
age: [null, Validators.min(18)],
});
onSubmit() {
const validData = validatedFormData(this.userForm);
if (validData) {
// Form is valid, submit clean data
this.userService.createUser(validData);
} else {
// Form is invalid, errors are now visible
console.log("Please fix form errors");
}
}
}// Using with async operations
export class ProfileComponent {
profileForm: DataFormGroup<ProfileUpdate> = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
bio: [null], // Optional
website: [null, Validators.pattern(/^https?://.+/)]
});
async updateProfile() {
const updateData = validatedFormData(this.profileForm);
if (!updateData) {
this.showErrorMessage('Please fix the form errors');
return;
}
try {
await this.profileService.update(updateData);
this.showSuccessMessage('Profile updated successfully');
} catch (error) {
this.showErrorMessage('Failed to update profile');
}
}
}// Type-safe form data extraction
interface ContactForm {
name: string;
email: string;
message: string;
newsletter?: boolean;
}
const contactForm: DataFormGroup<ContactForm> = this.fb.group({
name: ["", Validators.required],
email: ["", [Validators.required, Validators.email]],
message: ["", [Validators.required, Validators.minLength(10)]],
newsletter: [null],
});
const formData = validatedFormData(contactForm);
if (formData) {
// TypeScript knows formData is ContactForm with null values removed
console.log(formData.name); // string
console.log(formData.email); // string
console.log(formData.newsletter); // boolean | undefined (null was removed)
}See
- DataFormGroup Type-safe form group interface
- markFormDirty Function used internally to mark invalid controls
- replaceNulls Function used internally to clean the data
Interfaces
DataFormGroup
Defined in: libs/ngx-utils/src/lib/form/form.interfaces.ts:254
Interface for a type-safe Angular reactive form group
This interface extends Angular's UntypedFormGroup to provide strong typing for both form controls and form values. It ensures that the form structure matches the data type it represents, providing compile-time type safety and better developer experience.
The interface bridges the gap between Angular's form system and TypeScript's type system, allowing developers to work with forms in a type-safe manner while maintaining compatibility with Angular's reactive forms API.
Key benefits:
- Type-safe access to form controls
- Type-safe access to form values
- IntelliSense support for form properties
- Compile-time error detection for form structure mismatches
- Seamless integration with form utility functions
Examples
// Define the data structure
interface ContactForm {
firstName: string;
lastName: string;
email: string;
phone?: string;
message: string;
}
// Create a type-safe form
export class ContactComponent {
contactForm: DataFormGroup<ContactForm> = this.fb.group({
firstName: ["", Validators.required],
lastName: ["", Validators.required],
email: ["", [Validators.required, Validators.email]],
phone: [null],
message: ["", [Validators.required, Validators.minLength(10)]],
});
onSubmit() {
// Type-safe form validation and data extraction
const formData = validatedFormData(this.contactForm);
if (formData) {
// formData is properly typed as ContactForm
this.contactService.sendMessage(formData);
}
}
}// Advanced usage with nested forms
interface UserProfile {
personal: {
firstName: string;
lastName: string;
birthDate: Date;
};
contact: {
email: string;
phone: string;
};
preferences: {
newsletter: boolean;
notifications: boolean;
};
}
export class ProfileComponent {
profileForm: DataFormGroup<UserProfile> = this.fb.group({
personal: this.fb.group({
firstName: ["", Validators.required],
lastName: ["", Validators.required],
birthDate: [null, Validators.required],
}),
contact: this.fb.group({
email: ["", [Validators.required, Validators.email]],
phone: ["", Validators.required],
}),
preferences: this.fb.group({
newsletter: [false],
notifications: [true],
}),
});
// Type-safe access to nested controls
get emailControl() {
return this.profileForm.controls.contact.controls.email;
}
}// Using with dynamic forms
interface DynamicField {
id: string;
label: string;
value: string;
required: boolean;
}
export class DynamicFormComponent {
dynamicForm: DataFormGroup<Record<string, string>> = this.fb.group({});
addField(field: DynamicField) {
const validators = field.required ? [Validators.required] : [];
this.dynamicForm.addControl(
field.id,
new FormControl(field.value, validators),
);
}
getFormData() {
return validatedFormData(this.dynamicForm);
}
}See
- DataFormValues Type for form values structure
- DataFormControls Type for form controls structure
- UntypedFormGroup Angular's base form group class
- validatedFormData Function for extracting validated form data
- markFormDirty Function for marking form controls as dirty
Extends
UntypedFormGroup
Type Parameters
T
The data type that the form represents
Accessors
asyncValidator
Get Signature
get asyncValidator(): AsyncValidatorFn | null;Defined in: node_modules/@angular/forms/types/forms.d.ts:2571
Returns the function that is used to determine the validity of this control asynchronously.
If multiple validators have been added, this will be a single composed function.
See Validators.compose() for additional information.
Returns
AsyncValidatorFn | null
Set Signature
set asyncValidator(asyncValidatorFn): void;Defined in: node_modules/@angular/forms/types/forms.d.ts:2572
Parameters
asyncValidatorFn
AsyncValidatorFn | null
Returns
void
Inherited from
UntypedFormGroup.asyncValidator;dirty
Get Signature
get dirty(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2659
A control is dirty if the user has changed the value
in the UI.
Returns
boolean
True if the user has changed the value of this control in the UI; compare pristine.
Programmatic changes to a control's value do not mark it dirty.
Inherited from
UntypedFormGroup.dirty;disabled
Get Signature
get disabled(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2626
A control is disabled when its status is DISABLED.
Disabled controls are exempt from validation checks and are not included in the aggregate value of their ancestor controls.
See
AbstractControl.status
Returns
boolean
True if the control is disabled, false otherwise.
Inherited from
UntypedFormGroup.disabled;enabled
Get Signature
get enabled(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2636
A control is enabled as long as its status is not DISABLED.
See
AbstractControl.status
Returns
boolean
True if the control has any status other than 'DISABLED', false if the status is 'DISABLED'.
Inherited from
UntypedFormGroup.enabled;invalid
Get Signature
get invalid(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2605
A control is invalid when its status is INVALID.
See
AbstractControl.status
Returns
boolean
True if this control has failed one or more of its validation checks, false otherwise.
Inherited from
UntypedFormGroup.invalid;parent
Get Signature
get parent(): FormGroup<any> | FormArray<any> | null;Defined in: node_modules/@angular/forms/types/forms.d.ts:2576
The parent control.
Returns
FormGroup<any> | FormArray<any> | null
Inherited from
UntypedFormGroup.parent;pending
Get Signature
get pending(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2614
A control is pending when its status is PENDING.
See
AbstractControl.status
Returns
boolean
True if this control is in the process of conducting a validation check, false otherwise.
Inherited from
UntypedFormGroup.pending;pristine
Get Signature
get pristine(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2649
A control is pristine if the user has not yet changed
the value in the UI.
Returns
boolean
True if the user has not yet changed the value in the UI; compare dirty.
Programmatic changes to a control's value do not mark it dirty.
Set Signature
set pristine(value): void;Defined in: node_modules/@angular/forms/types/forms.d.ts:2650
Parameters
value
boolean
Returns
void
Inherited from
UntypedFormGroup.pristine;root
Get Signature
get root(): AbstractControl;Defined in: node_modules/@angular/forms/types/forms.d.ts:3201
Retrieves the top-level ancestor of this control.
Returns
AbstractControl
Inherited from
UntypedFormGroup.root;status
Get Signature
get status(): FormControlStatus;Defined in: node_modules/@angular/forms/types/forms.d.ts:2585
The validation status of the control.
See
FormControlStatus
These status values are mutually exclusive, so a control cannot be both valid AND invalid or invalid AND disabled.
Returns
FormControlStatus
Set Signature
set status(value): void;Defined in: node_modules/@angular/forms/types/forms.d.ts:2586
Parameters
value
FormControlStatus
Returns
void
Inherited from
UntypedFormGroup.status;touched
Get Signature
get touched(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2666
True if the control is marked as touched.
A control is marked touched once the user has triggered
a blur event on it.
Returns
boolean
Set Signature
set touched(value): void;Defined in: node_modules/@angular/forms/types/forms.d.ts:2667
Parameters
value
boolean
Returns
void
Inherited from
UntypedFormGroup.touched;untouched
Get Signature
get untouched(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2675
True if the control has not been marked as touched
A control is untouched if the user has not yet triggered
a blur event on it.
Returns
boolean
Inherited from
UntypedFormGroup.untouched;updateOn
Get Signature
get updateOn(): FormHooks;Defined in: node_modules/@angular/forms/types/forms.d.ts:2716
Reports the update strategy of the AbstractControl (meaning
the event on which the control updates itself).
Possible values: 'change' | 'blur' | 'submit'
Default value: 'change'
Returns
FormHooks
Inherited from
UntypedFormGroup.updateOn;valid
Get Signature
get valid(): boolean;Defined in: node_modules/@angular/forms/types/forms.d.ts:2596
A control is valid when its status is VALID.
See
AbstractControl.status
Returns
boolean
True if the control has passed all of its validation tests, false otherwise.
Inherited from
UntypedFormGroup.valid;validator
Get Signature
get validator(): ValidatorFn | null;Defined in: node_modules/@angular/forms/types/forms.d.ts:2564
Returns the function that is used to determine the validity of this control synchronously.
If multiple validators have been added, this will be a single composed function.
See Validators.compose() for additional information.
Returns
ValidatorFn | null
Set Signature
set validator(validatorFn): void;Defined in: node_modules/@angular/forms/types/forms.d.ts:2565
Parameters
validatorFn
ValidatorFn | `n
