CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ngx-bootstrap

Angular Bootstrap component library providing comprehensive UI components for Angular applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utilities-infrastructure.mddocs/

Utilities & Infrastructure

Core utilities for positioning, theming, date manipulation, component loading, and other infrastructure functionality.

Capabilities

Positioning

Advanced positioning calculations for overlays, tooltips, dropdowns, and other positioned elements.

/**
 * Service for element positioning calculations
 */
@Injectable()
class PositioningService {
  /** Position target element relative to host element */
  position(
    hostElement: HTMLElement,
    targetElement: HTMLElement,
    placement?: string,
    appendToBody?: boolean
  ): { top: number; left: number };

  /** Get available positions for element */
  getAvailablePositions(
    hostElement: HTMLElement,
    targetElement: HTMLElement
  ): string[];

  /** Check if element fits in viewport */
  checkFit(
    element: HTMLElement,
    placement: string
  ): boolean;

  /** Auto position element based on available space */
  autoPosition(
    hostElement: HTMLElement,
    targetElement: HTMLElement,
    preferredPlacement?: string
  ): { top: number; left: number; placement: string };
}

/**
 * Core positioning utility class
 */
class Positioning {
  /** Get element position relative to document */
  static position(element: HTMLElement, round?: boolean): { width: number; height: number; top: number; left: number };

  /** Get element offset */
  static offset(element: HTMLElement, round?: boolean): { width: number; height: number; top: number; left: number };

  /** Position elements */
  static positionElements(
    hostElement: HTMLElement,
    targetElement: HTMLElement,
    placement: string,
    appendToBody?: boolean,
    options?: PositioningOptions
  ): { top: number; left: number };
}

/**
 * Positioning configuration options
 */
interface PositioningOptions {
  /** Offset from host element */
  offset?: number;
  /** Allow flipping placement */
  allowFlip?: boolean;
  /** Viewport boundaries */
  boundary?: 'viewport' | 'window' | HTMLElement;
  /** Placement modifiers */
  modifiers?: PositioningModifier[];
}

/**
 * Positioning modifier interface
 */
interface PositioningModifier {
  /** Modifier name */
  name: string;
  /** Modifier options */
  options?: any;
  /** Modifier function */
  fn?: (data: any, options: any) => any;
}

/**
 * Available Bootstrap positioning options
 */
type AvailableBSPositions = 
  | 'top' | 'bottom' | 'left' | 'right'
  | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
  | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom';

/**
 * Bootstrap 5 placement options
 */
type PlacementForBs5 = 
  | 'auto' | 'auto-start' | 'auto-end'
  | 'top' | 'top-start' | 'top-end'
  | 'bottom' | 'bottom-start' | 'bottom-end'
  | 'right' | 'right-start' | 'right-end'
  | 'left' | 'left-start' | 'left-end';

/**
 * Utility functions for positioning
 */
declare function positionElements(
  hostElement: HTMLElement,
  targetElement: HTMLElement,
  placement: string,
  appendToBody?: boolean
): { top: number; left: number };

declare function checkMargins(margin: string | number): { top: number; right: number; bottom: number; left: number };

Usage Example:

import { PositioningService, positionElements } from 'ngx-bootstrap/positioning';

@Component({
  template: `
    <button #hostBtn class="btn btn-primary" (click)="showTooltip()">
      Host Element
    </button>
    
    <div #tooltipEl class="custom-tooltip" [style.display]="tooltipVisible ? 'block' : 'none'">
      Custom positioned tooltip
    </div>
  `,
  providers: [PositioningService]
})
export class PositioningExampleComponent {
  @ViewChild('hostBtn') hostButton: ElementRef;
  @ViewChild('tooltipEl') tooltipElement: ElementRef;
  
  tooltipVisible = false;

  constructor(private positioning: PositioningService) {}

  showTooltip() {
    this.tooltipVisible = true;
    
    // Position using service
    const position = this.positioning.position(
      this.hostButton.nativeElement,
      this.tooltipElement.nativeElement,
      'top'
    );
    
    // Apply position
    const tooltip = this.tooltipElement.nativeElement;
    tooltip.style.top = position.top + 'px';
    tooltip.style.left = position.left + 'px';
    
    // Alternative: Use utility function
    const utilityPosition = positionElements(
      this.hostButton.nativeElement,
      this.tooltipElement.nativeElement,
      'bottom',
      true
    );
    
    console.log('Service position:', position);
    console.log('Utility position:', utilityPosition);
  }
}

Theme & Version Management

Utilities for managing Bootstrap theme versions and component styling.

/**
 * Set Bootstrap theme version
 */
declare function setTheme(theme: AvailableBsVersions): void;

/**
 * Get current Bootstrap version information
 */
declare function getBsVer(): IBsVersion;

/**
 * Current Bootstrap version information
 */
declare const currentBsVersion: IBsVersion;

/**
 * Bootstrap version interface
 */
interface IBsVersion {
  /** Is Bootstrap 3 */
  isBs3: boolean;
  /** Is Bootstrap 4 */
  isBs4: boolean;
  /** Is Bootstrap 5 */
  isBs5: boolean;
}

/**
 * Available Bootstrap versions
 */
type AvailableBsVersions = 'bs3' | 'bs4' | 'bs5';

/**
 * Bootstrap version configurations
 */
interface BsVersions {
  [key: string]: IBsVersion;
}

Usage Example:

import { setTheme, getBsVer, currentBsVersion } from 'ngx-bootstrap/utils';

@Component({
  template: `
    <div class="version-info">
      <h5>Current Bootstrap Version</h5>
      <div class="alert alert-info">
        <div *ngIf="version.isBs3">Bootstrap 3 is active</div>
        <div *ngIf="version.isBs4">Bootstrap 4 is active</div>
        <div *ngIf="version.isBs5">Bootstrap 5 is active</div>
      </div>
      
      <div class="btn-group" role="group">
        <button class="btn btn-outline-primary" (click)="switchTheme('bs3')">
          Bootstrap 3
        </button>
        <button class="btn btn-outline-primary" (click)="switchTheme('bs4')">
          Bootstrap 4
        </button>
        <button class="btn btn-outline-primary" (click)="switchTheme('bs5')">
          Bootstrap 5
        </button>
      </div>
    </div>
  `
})
export class ThemeManagerComponent implements OnInit {
  version: IBsVersion;

  ngOnInit() {
    this.version = getBsVer();
    console.log('Current version:', currentBsVersion);
  }

  switchTheme(theme: AvailableBsVersions) {
    setTheme(theme);
    this.version = getBsVer();
    console.log('Switched to:', theme, this.version);
  }
}

Trigger Management

Advanced trigger handling for events, outside clicks, and keyboard interactions.

/**
 * Advanced trigger handling with multiple options
 */
declare function listenToTriggersV2(
  renderer: Renderer2,
  options: TriggerOptions
): () => void;

/**
 * Register outside click detection
 */
declare function registerOutsideClick(
  renderer: Renderer2,
  options: OutsideClickOptions
): () => void;

/**
 * Register escape key handling
 */
declare function registerEscClick(
  renderer: Renderer2,
  options: EscClickOptions
): () => void;

/**
 * Trigger configuration options
 */
interface TriggerOptions {
  /** Target element */
  target: HTMLElement;
  /** Trigger events */
  triggers: string;
  /** Show callback */
  show: () => void;
  /** Hide callback */
  hide: () => void;
  /** Toggle callback */
  toggle?: () => void;
}

/**
 * Outside click options
 */
interface OutsideClickOptions {
  /** Target element */
  targets: HTMLElement[];
  /** Outside click callback */
  outsideClick: () => void;
  /** Exclude elements */
  exclude?: HTMLElement[];
}

/**
 * Escape click options
 */
interface EscClickOptions {
  /** Escape key callback */
  escClick: () => void;
}

/**
 * Trigger utility class
 */
class Trigger {
  /** Parse trigger string */
  static parseTriggers(triggers: string): string[];
  /** Support manual triggers */
  static isManual(triggers: string): boolean;
}

Usage Example:

import { 
  listenToTriggersV2, 
  registerOutsideClick, 
  registerEscClick 
} from 'ngx-bootstrap/utils';

@Component({
  template: `
    <button #triggerBtn class="btn btn-primary">
      Custom Trigger Element
    </button>
    
    <div #dropdown class="custom-dropdown" [style.display]="isOpen ? 'block' : 'none'">
      <div class="dropdown-content">
        Custom dropdown content
        <button class="btn btn-sm btn-secondary" (click)="closeDropdown()">
          Close
        </button>
      </div>
    </div>
  `
})
export class CustomTriggerComponent implements OnInit, OnDestroy {
  @ViewChild('triggerBtn') triggerButton: ElementRef;
  @ViewChild('dropdown') dropdown: ElementRef;
  
  isOpen = false;
  private unsubscribeTriggers: () => void;
  private unsubscribeOutsideClick: () => void;
  private unsubscribeEscClick: () => void;

  constructor(private renderer: Renderer2) {}

  ngOnInit() {
    // Setup advanced triggers
    this.unsubscribeTriggers = listenToTriggersV2(this.renderer, {
      target: this.triggerButton.nativeElement,
      triggers: 'click hover:500',
      show: () => this.showDropdown(),
      hide: () => this.hideDropdown(),
      toggle: () => this.toggleDropdown()
    });

    // Setup outside click
    this.unsubscribeOutsideClick = registerOutsideClick(this.renderer, {
      targets: [this.triggerButton.nativeElement, this.dropdown.nativeElement],
      outsideClick: () => this.hideDropdown()
    });

    // Setup escape key
    this.unsubscribeEscClick = registerEscClick(this.renderer, {
      escClick: () => this.hideDropdown()
    });
  }

  ngOnDestroy() {
    if (this.unsubscribeTriggers) this.unsubscribeTriggers();
    if (this.unsubscribeOutsideClick) this.unsubscribeOutsideClick();
    if (this.unsubscribeEscClick) this.unsubscribeEscClick();
  }

  showDropdown() {
    this.isOpen = true;
  }

  hideDropdown() {
    this.isOpen = false;
  }

  toggleDropdown() {
    this.isOpen = !this.isOpen;
  }

  closeDropdown() {
    this.hideDropdown();
  }
}

Component Loading

Dynamic component loading and management utilities for programmatic component creation.

/**
 * Component loader for dynamic component creation
 */
class ComponentLoader<T> {
  /** Provide component to load */
  provide(component: ComponentType<T>): ComponentLoader<T>;
  
  /** Set container for component */
  to(container?: string | ElementRef): ComponentLoader<T>;
  
  /** Configure positioning */
  position(opts?: PositioningOptions): ComponentLoader<T>;
  
  /** Show component */
  show(opts?: ComponentLoaderOptions): ComponentRef<T>;
  
  /** Hide component */
  hide(): ComponentLoader<T>;
  
  /** Toggle component visibility */
  toggle(): ComponentLoader<T>;
  
  /** Dispose of component */
  dispose(): void;
  
  /** Get component instance */
  getInstance(): ComponentRef<T>;
  
  /** Check if component is shown */
  isShown(): boolean;
}

/**
 * Factory for creating component loaders
 */
@Injectable()
class ComponentLoaderFactory {
  /** Create component loader */
  createLoader<T>(
    elementRef: ElementRef,
    viewContainerRef: ViewContainerRef,
    renderer: Renderer2
  ): ComponentLoader<T>;
}

/**
 * Reference to loaded component
 */
class BsComponentRef<T> {
  /** Template reference */
  templateRef?: TemplateRef<T>;
  /** View container reference */
  viewContainer?: ViewContainerRef;
  /** Component location */
  location?: ElementRef;

  /** Hide component */
  hide(): void;
  /** Show component */
  show(): void;
  /** Toggle component */
  toggle(): void;
}

/**
 * Reference to component content
 */
class ContentRef {
  /** Nodes collection */
  nodes: any[];
  /** View reference */
  viewRef?: ViewRef;
  /** Component reference */
  componentRef?: ComponentRef<any>;

  /** Detach view */
  detach(): void;
  /** Attach view */
  attach(): void;
}

/**
 * Component loader options
 */
interface ComponentLoaderOptions {
  /** Initial state for component */
  initialState?: { [key: string]: any };
  /** Providers for component */
  providers?: StaticProvider[];
  /** Injector for component */
  injector?: Injector;
}

Usage Example:

import { 
  ComponentLoaderFactory, 
  ComponentLoader,
  BsComponentRef 
} from 'ngx-bootstrap/component-loader';

// Dynamic component to load
@Component({
  template: ` 
    <div class="alert alert-info">
      <h5>{{title}}</h5>
      <p>{{message}}</p>
      <button class="btn btn-primary" (click)="action()">
        {{actionText}}
      </button>
    </div>
  `
})
export class DynamicAlertComponent {
  title = 'Dynamic Alert';
  message = 'This component was loaded dynamically';
  actionText = 'OK';
  
  action() {
    console.log('Dynamic component action triggered');
  }
}

@Component({
  template: `
    <div class="component-loader-demo">
      <button class="btn btn-primary" (click)="loadComponent()">
        Load Dynamic Component
      </button>
      
      <button class="btn btn-success ml-2" (click)="showComponent()" [disabled]="!componentLoader">
        Show Component
      </button>
      
      <button class="btn btn-warning ml-2" (click)="hideComponent()" [disabled]="!componentLoader">
        Hide Component
      </button>
      
      <button class="btn btn-danger ml-2" (click)="disposeComponent()" [disabled]="!componentLoader">
        Dispose Component
      </button>
      
      <!-- Container for dynamic component -->
      <div #componentContainer class="mt-3"></div>
    </div>
  `
})
export class ComponentLoaderDemoComponent {
  @ViewChild('componentContainer') containerRef: ElementRef;
  
  private componentLoader: ComponentLoader<DynamicAlertComponent>;

  constructor(
    private elementRef: ElementRef,
    private viewContainerRef: ViewContainerRef,
    private renderer: Renderer2,
    private componentLoaderFactory: ComponentLoaderFactory
  ) {}

  loadComponent() {
    // Create component loader
    this.componentLoader = this.componentLoaderFactory
      .createLoader<DynamicAlertComponent>(
        this.elementRef,
        this.viewContainerRef,
        this.renderer
      );

    // Configure and show component
    const componentRef = this.componentLoader
      .provide(DynamicAlertComponent)
      .to(this.containerRef)
      .show({
        initialState: {
          title: 'Dynamically Loaded',
          message: 'This component was created using ComponentLoader',
          actionText: 'Close'
        }
      });

    // Access component instance
    if (componentRef && componentRef.instance) {
      componentRef.instance.action = () => {
        this.hideComponent();
      };
    }
  }

  showComponent() {
    if (this.componentLoader) {
      this.componentLoader.show();
    }
  }

  hideComponent() {
    if (this.componentLoader) {
      this.componentLoader.hide();
    }
  }

  disposeComponent() {
    if (this.componentLoader) {
      this.componentLoader.dispose();
      this.componentLoader = null;
    }
  }
}

Date/Time Utilities (Chronos)

Comprehensive date and time manipulation library with extensive functionality.

/**
 * Date manipulation functions
 */
declare function add(date: Date, amount: number, unit: TimeUnit): Date;
declare function subtract(date: Date, amount: number, unit: TimeUnit): Date;
declare function parseDate(input: string, format?: string, locale?: string): Date;
declare function formatDate(date: Date, format: string, locale?: string): string;
declare function utcAsLocal(date: Date): Date;

/**
 * Date getters
 */
declare function getDay(date: Date): number;
declare function getMonth(date: Date): number;
declare function getFullYear(date: Date): number;
declare function isFirstDayOfWeek(date: Date, firstDayOfWeek: number): boolean;
declare function isSameYear(date1: Date, date2: Date): boolean;
declare function isSameDay(date1: Date, date2: Date): boolean;
declare function isSameMonth(date1: Date, date2: Date): boolean;
declare function getFirstDayOfMonth(date: Date): Date;

/**
 * Date comparisons
 */
declare function isAfter(date1: Date, date2: Date): boolean;
declare function isBefore(date1: Date, date2: Date): boolean;
declare function isSame(date1: Date, date2: Date, unit?: TimeUnit): boolean;
declare function isDisabledDay(
  date: Date, 
  daysDisabled: number[], 
  minDate?: Date, 
  maxDate?: Date
): boolean;

/**
 * Date setters
 */
declare function shiftDate(date: Date, amount: number, unit: TimeUnit): Date;
declare function setFullDate(date: Date, year: number, month: number, day: number): Date;

/**
 * Start/End operations
 */
declare function startOf(date: Date, unit: TimeUnit): Date;
declare function endOf(date: Date, unit: TimeUnit): Date;

/**
 * Validation functions
 */
declare function isArray(input: any): boolean;
declare function isDate(input: any): boolean;
declare function isDateValid(date: Date): boolean;

/**
 * Locale management
 */
declare function listLocales(): string[];
declare function getLocale(key?: string): any;
declare function updateLocale(key: string, values: any): void;
declare function defineLocale(key: string, config: any): void;
declare function getSetGlobalLocale(key?: string): string;

/**
 * Locale data class
 */
class LocaleData {
  /** Locale abbreviation */
  abbr: string;
  /** Month names */
  months: string[];
  /** Short month names */
  monthsShort: string[];
  /** Weekday names */
  weekdays: string[];
  /** Short weekday names */
  weekdaysShort: string[];
  /** Minimal weekday names */
  weekdaysMin: string[];
}

/**
 * Time units enumeration
 */
type TimeUnit = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond';

Usage Example:

import {
  add,
  subtract,
  parseDate,
  formatDate,
  isSameDay,
  startOf,
  endOf,
  defineLocale,
  getLocale
} from 'ngx-bootstrap/chronos';
import { esLocale } from 'ngx-bootstrap/locale';

@Component({
  template: `
    <div class="chronos-demo">
      <h5>Date Manipulation</h5>
      
      <div class="mb-3">
        <label>Current Date: {{currentDate | date:'medium'}}</label>
      </div>
      
      <div class="mb-3">
        <label>Add 7 days: {{futureDate | date:'medium'}}</label>
      </div>
      
      <div class="mb-3">
        <label>Subtract 1 month: {{pastDate | date:'medium'}}</label>
      </div>
      
      <div class="mb-3">
        <label>Start of month: {{monthStart | date:'medium'}}</label>
      </div>
      
      <div class="mb-3">
        <label>End of month: {{monthEnd | date:'medium'}}</label>
      </div>
      
      <div class="mb-3">
        <label>Custom format: {{customFormatted}}</label>
      </div>
      
      <div class="mb-3">
        <label>Spanish locale: {{spanishFormatted}}</label>
      </div>
      
      <div class="form-group">
        <label for="dateInput">Parse Date:</label>
        <input 
          type="text" 
          class="form-control" 
          id="dateInput"
          [(ngModel)]="dateInput"
          (input)="parseInputDate()"
          placeholder="YYYY-MM-DD">
        <small class="form-text text-muted">
          Parsed: {{parsedDate | date:'medium'}}
        </small>
      </div>
    </div>
  `
})
export class ChronosExampleComponent implements OnInit {
  currentDate = new Date();
  futureDate: Date;
  pastDate: Date;
  monthStart: Date;
  monthEnd: Date;
  customFormatted: string;
  spanishFormatted: string;
  
  dateInput = '2023-12-25';
  parsedDate: Date;

  ngOnInit() {
    // Date manipulation
    this.futureDate = add(this.currentDate, 7, 'day');
    this.pastDate = subtract(this.currentDate, 1, 'month');
    
    // Start/end operations
    this.monthStart = startOf(this.currentDate, 'month');
    this.monthEnd = endOf(this.currentDate, 'month');
    
    // Custom formatting
    this.customFormatted = formatDate(this.currentDate, 'dddd, MMMM Do YYYY');
    
    // Setup Spanish locale
    defineLocale('es', esLocale);
    this.spanishFormatted = formatDate(this.currentDate, 'dddd, MMMM Do YYYY', 'es');
    
    // Parse initial date
    this.parseInputDate();
    
    // Demonstrate comparisons
    this.demonstrateComparisons();
  }

  parseInputDate() {
    try {
      this.parsedDate = parseDate(this.dateInput, 'YYYY-MM-DD');
    } catch (error) {
      console.log('Invalid date format');
      this.parsedDate = null;
    }
  }

  demonstrateComparisons() {
    const today = new Date();
    const tomorrow = add(today, 1, 'day');
    
    console.log('Is same day?', isSameDay(today, tomorrow)); // false
    console.log('Is tomorrow after today?', isAfter(tomorrow, today)); // true
    console.log('Is today before tomorrow?', isBefore(today, tomorrow)); // true
  }
}

General Utilities

Additional utility functions and classes for common operations.

/**
 * Linked list implementation
 */
class LinkedList<T> {
  /** Add item to list */
  add(item: T, index?: number): void;
  /** Remove item from list */
  remove(index: number): void;
  /** Get item at index */
  get(index: number): T;
  /** Get list length */
  length(): number;
  /** Convert to array */
  toArray(): T[];
}

/**
 * General utility functions
 */
class Utils {
  /** Reflow DOM element */
  static reflow(element: HTMLElement): void;
  /** Get computed style */
  static getComputedStyle(element: HTMLElement): CSSStyleDeclaration;
  /** Check if element is visible */
  static isVisible(element: HTMLElement): boolean;
}

/**
 * Change detection decorator
 */
declare function OnChange(): PropertyDecorator;

/**
 * Warning utility that shows message only once
 */
declare function warnOnce(message: string): void;

/**
 * Browser object facades
 */
declare const window: Window;
declare const document: Document;

Usage Example:

import { LinkedList, Utils, warnOnce } from 'ngx-bootstrap/utils';

@Component({
  template: `
    <div class="utils-demo">
      <h5>Utility Functions Demo</h5>
      
      <div class="mb-3">
        <button class="btn btn-primary" (click)="addToList()">Add to List</button>
        <button class="btn btn-secondary ml-2" (click)="removeFromList()">Remove Last</button>
        <button class="btn btn-info ml-2" (click)="showListContents()">Show List</button>
      </div>
      
      <div class="mb-3">
        <button class="btn btn-warning" (click)="triggerWarning()">Trigger Warning</button>
        <button class="btn btn-success ml-2" (click)="checkVisibility()" #visibilityBtn>Check Visibility</button>
      </div>
      
      <div class="alert alert-info" *ngIf="listContents.length > 0">
        <strong>List Contents:</strong>
        <ul class="mb-0">
          <li *ngFor="let item of listContents">{{item}}</li>
        </ul>
      </div>
    </div>
  `
})
export class UtilsExampleComponent {
  @ViewChild('visibilityBtn') visibilityButton: ElementRef;
  
  private myList = new LinkedList<string>();
  listContents: string[] = [];
  private itemCounter = 1;

  addToList() {
    const item = `Item ${this.itemCounter++}`;
    this.myList.add(item);
    this.updateListContents();
  }

  removeFromList() {
    if (this.myList.length() > 0) {
      this.myList.remove(this.myList.length() - 1);
      this.updateListContents();
    }
  }

  showListContents() {
    this.updateListContents();
    console.log('Current list:', this.listContents);
  }

  private updateListContents() {
    this.listContents = this.myList.toArray();
  }

  triggerWarning() {
    warnOnce('This warning will only appear once per session');
  }

  checkVisibility() {
    if (this.visibilityButton) {
      const isVisible = Utils.isVisible(this.visibilityButton.nativeElement);
      const computedStyle = Utils.getComputedStyle(this.visibilityButton.nativeElement);
      
      console.log('Button is visible:', isVisible);
      console.log('Button computed style:', computedStyle);
      
      // Demonstrate reflow
      Utils.reflow(this.visibilityButton.nativeElement);
    }
  }
}

docs

form-controls.md

index.md

interactive-components.md

navigation-layout.md

overlays-popovers.md

utilities-infrastructure.md

tile.json