/**
* @module module:lib/engine/NgxParentComponentDirective
* @description Directive base for parent container components used by the rendering system.
* @summary Provides NgxParentComponentDirective which offers inputs for children metadata,
* column/row configuration and parent component wiring used by layout and container components.
*
* @link {@link NgxParentComponentDirective}
*/
import { Directive, Input, OnInit } from '@angular/core';
import { NgxComponentDirective } from './NgxComponentDirective';
import { FormParent, KeyValue } from './types';
import { FieldDefinition, IPagedComponentProperties, UIMediaBreakPoints, UIMediaBreakPointsType, UIModelMetadata } from '@decaf-ts/ui-decorators';
import { Model } from '@decaf-ts/decorator-validation';
import { IComponentProperties } from './interfaces';
import { Subscription, timer } from 'rxjs';
/**
* @description Layout component for creating responsive grid layouts in Angular applications.
* @summary This component provides a flexible grid system that can be configured with dynamic
* rows and columns. It supports responsive breakpoints and can render child components within
* the grid structure. The component extends NgxComponentDirective to inherit common functionality
* and integrates with the model and component renderer systems.
*
* @class NgxParentComponentDirective
* @extends {NgxComponentDirective}
* @implements {OnInit}
*/
@Directive()
export class NgxParentComponentDirective extends NgxComponentDirective implements OnInit {
/**
* @description Unique identifier for the current record.
* @summary A unique identifier for the current record being displayed or manipulated.
* This is typically used in conjunction with the primary key for operations on specific records.
*
* @type {string | number}
*/
@Input()
page: number = 1;
/**
* @description Unique identifier for the current record.
* @summary A unique identifier for the current record being displayed or manipulated.
* This is typically used in conjunction with the primary key for operations on specific records.
*
* @type {string | number}
*/
@Input()
pages: number | IPagedComponentProperties[] = 1;
/**
* @description Array of UI model metadata for the currently active page.
* @summary Contains only the UI model metadata for fields that should be displayed
* on the currently active page. This is a filtered subset of the children array,
* updated whenever the user navigates between pages.
*
* @type { UIModelMetadata | UIModelMetadata[] | FieldDefinition | FieldDefinition[] | undefined }
*/
activePage: UIModelMetadata | UIModelMetadata[] | FieldDefinition | FieldDefinition[] | undefined = undefined;
/**
* @description The currently active page number.
* @summary Tracks which page of the multi-step form is currently being displayed.
* This property is updated as users navigate through the form steps using
* the next/back buttons or programmatic navigation.
*
* @type {number}
*/
activeIndex: number = 1;
/**
* @description The parent form object that represents the parent-child relationship in the form hierarchy.
* @summary This input binds the parent form object to the directive, enabling hierarchical form structures.
* It allows the directive to interact with the parent form and manage child components effectively.
*
* @type {FormParent}
*/
@Input()
parentForm!: FormParent;
/**
* @description Array of UI model metadata for all form fields.
* @summary Contains the complete collection of UI model metadata that defines
* the structure, validation, and presentation of form fields across all pages.
* Each metadata object contains information about field type, validation rules,
* page assignment, and display properties.
*
* @type {UIModelMetadata[]}
*/
@Input()
children: UIModelMetadata[] | IComponentProperties[] | FieldDefinition[] | KeyValue[] = [];
/**
* @description Number of columns or array of column definitions for the grid layout.
* @summary Defines the column structure of the grid. When a number is provided, it creates
* that many equal-width columns. When an array is provided, each element can define specific
* column properties or sizing. This allows for flexible grid layouts that can adapt to
* different content requirements.
*
* @type {(number | string[])}
* @default 1
*/
@Input()
cols: number | string[] = 1;
/**
* @description Number of rows or array of row definitions for the grid layout.
* @summary Defines the row structure of the grid. When a number is provided, it creates
* that many equal-height rows. When an array is provided, each element can define specific
* row properties or sizing. This provides control over vertical spacing and content organization.
*
* @type {(number | string[])}
* @default 1
*/
@Input()
rows: number | KeyValue[] | string[] = 1;
/**
* @description Defines the body style of the card.
* @summary Specifies the appearance of the card body, allowing customization
* between default, small, or blank styles. This input is used to control the
* visual presentation of the card content.
* @type {'default' | 'small' | 'blank'}
* @default 'default'
*/
@Input()
cardBody: 'default' | 'small' | 'blank' = 'default';
/**
* @description Specifies the type of the card.
* @summary Determines the card's visual style, such as clear or shadowed.
* This input allows for flexible styling of the card component to match
* different design requirements.
* @type {'clear' | 'shadow'}
* @default 'clear'
*/
@Input()
cardType: 'clear' | 'shadow' = 'clear';
/**
* @description Media breakpoint for responsive behavior.
* @summary Determines the responsive breakpoint at which the layout should adapt.
* This affects how the grid behaves on different screen sizes, allowing for
* mobile-first or desktop-first responsive design patterns. The breakpoint
* is automatically processed to ensure compatibility with the UI framework.
*
* @type {UIMediaBreakPointsType}
* @default 'medium'
*/
@Input()
breakpoint?: UIMediaBreakPointsType | string = UIMediaBreakPoints.MEDIUM;
/**
* @description Determines if the layout should match the parent container's size or configuration.
* @summary Boolean flag that controls whether the component should adapt its layout to match its parent.
* When true, the component will attempt to align or size itself according to the parent container.
*
* @type {boolean}
* @default true
*/
@Input()
match: boolean = true;
/**
* @description Preloads card placeholders for rendering.
* @summary Used to create an array of placeholder elements for card components,
* typically to reserve space or trigger rendering logic before actual data is loaded.
*
* @type {any[]}
* @default [undefined]
*/
preloadCards: string[] = new Array(1);
/**
* @description Subscription for timer-based operations.
* @summary Manages the timer subscription used for asynchronous operations
* like updating active children after page transitions. This subscription
* is cleaned up in ngOnDestroy to prevent memory leaks.
*
* @private
* @type {Subscription}
* @memberOf SteppedFormComponent
*/
protected timerSubscription!: Subscription;
async ngOnInit(model?: Model | string): Promise<void> {
if (model)
this.model = model as unknown as string;
if (this.model && !this.repository)
this._repository = this.repository;
}
override ngOnDestroy(): Promise<void> | void {
super.ngOnDestroy();
if (this.timerSubscription)
this.timerSubscription.unsubscribe();
}
protected getActivePage(page: number, firstClick: boolean = true): UIModelMetadata | UIModelMetadata[] | FieldDefinition | undefined {
if(firstClick || this.activeIndex !== page) {
const content = this.children[page] as FieldDefinition;
this.activePage = undefined;
this.preloadCards = [... new Array(1)];
this.timerSubscription = timer(25).subscribe(() =>
this.activePage = {... this.children[page] as FieldDefinition }
);
this.activeIndex = page;
if(content)
return content;
return undefined;
}
}
}
Source