Core package of ngx-formly - a dynamic (JSON powered) form library for Angular that brings unmatched maintainability to your application's forms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Utility functions and helpers for form manipulation, data binding, reactive programming, and field configuration management.
Utility functions for managing field properties and hidden properties.
/**
* Define a hidden (non-enumerable) property on an object
* @param field - The object to define the property on
* @param prop - The property name
* @param defaultValue - The default value for the property
*/
function defineHiddenProp(field: any, prop: string, defaultValue: any): void;
/**
* Check if a field has a valid key for model binding
* @param field - The field configuration to check
* @returns True if field has a key
*/
function hasKey(field: FormlyFieldConfig): boolean;Usage Example:
import { defineHiddenProp, hasKey } from '@ngx-formly/core';
// Define a hidden property for internal use
const field: FormlyFieldConfig = { key: 'username', type: 'input' };
defineHiddenProp(field, '_internalId', 'field_123');
// Check if field can be bound to model
if (hasKey(field)) {
console.log('Field will be bound to model property:', field.key);
}Functions for cloning, merging, and retrieving field values.
/**
* Deep clone a value, handling circular references and complex objects
* @param value - The value to clone
* @returns Deep cloned copy of the value
*/
function clone(value: any): any;
/**
* Reverse deep merge multiple objects, with later arguments taking precedence
* @param dest - The destination object
* @param args - Source objects to merge (later objects override earlier ones)
* @returns The merged object
*/
function reverseDeepMerge(dest: any, ...args: any[]): any;
/**
* Get the current value of a field from its form control or model
* @param field - The field configuration
* @returns The current field value
*/
function getFieldValue(field: FormlyFieldConfig): any;Usage Example:
import { clone, reverseDeepMerge, getFieldValue } from '@ngx-formly/core';
// Clone a complex object
const originalData = { user: { name: 'John', settings: { theme: 'dark' } } };
const clonedData = clone(originalData);
// Merge configuration objects
const baseConfig = { type: 'input', props: { label: 'Name' } };
const customConfig = { props: { placeholder: 'Enter name', required: true } };
const merged = reverseDeepMerge({}, baseConfig, customConfig);
// Result: { type: 'input', props: { label: 'Name', placeholder: 'Enter name', required: true } }
// Get current field value
const field: FormlyFieldConfig = {
key: 'email',
formControl: new FormControl('user@example.com')
};
const currentValue = getFieldValue(field); // 'user@example.com'Observable utilities for handling field changes and reactive updates.
/**
* Create an observable from a field expression or value
* @param field - The field configuration
* @param expression - The expression to observe (string, function, or observable)
* @param defaultValue - Default value if expression is undefined
* @returns Observable that emits when the expression changes
*/
function observe<T>(
field: FormlyFieldConfig,
expression: string | ((field: FormlyFieldConfig) => T) | Observable<T>,
defaultValue?: T
): Observable<T>;Usage Example:
import { observe } from '@ngx-formly/core';
import { map, distinctUntilChanged } from 'rxjs/operators';
// Observe field property changes
const field: FormlyFieldConfig = {
key: 'email',
type: 'input',
expressions: {
'props.disabled': 'model.isReadonly'
}
};
// Observe the disabled state
observe(field, 'props.disabled', false)
.pipe(
distinctUntilChanged(),
map(disabled => disabled ? 'Field is disabled' : 'Field is enabled')
)
.subscribe(status => console.log(status));
// Observe using a function
observe(field, (f) => f.formControl?.valid, false)
.subscribe(isValid => {
console.log('Field validity changed:', isValid);
});Utility component for grouping fields without additional wrapper markup.
/**
* Internal component for rendering field groups without wrapper markup
* Used by the form rendering system for fieldGroup configurations
*/
@Component({
selector: 'formly-group',
template: `<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>`
})
export class FormlyGroup {
/** The field configuration containing fieldGroup */
@Input() field: FormlyFieldConfig;
}Usage Example:
// Field configuration using fieldGroup
const fieldConfig: FormlyFieldConfig = {
fieldGroup: [
{
key: 'firstName',
type: 'input',
props: { label: 'First Name', required: true }
},
{
key: 'lastName',
type: 'input',
props: { label: 'Last Name', required: true }
}
],
fieldGroupClassName: 'row' // CSS class for the group
};/**
* Type for field expression that can be a string, function, or observable
*/
type FieldExpression<T = any> = string | ((field: FormlyFieldConfig) => T) | Observable<T>;
/**
* Map of field expressions for different properties
*/
interface FieldExpressions {
[property: string]: FieldExpression;
/** Expression for CSS class names */
className?: FieldExpression<string>;
/** Expression for hiding the field */
hide?: FieldExpression<boolean>;
/** Expression for disabling the field */
'props.disabled'?: FieldExpression<boolean>;
/** Expression for making the field required */
'props.required'?: FieldExpression<boolean>;
}
/**
* Interface for objects that can be cloned
*/
interface Cloneable {
clone?(): any;
}
/**
* Options for merge operations
*/
interface MergeOptions {
/** Whether to merge arrays by concatenating */
arrayMerge?: boolean;
/** Whether to clone values during merge */
clone?: boolean;
}/**
* Context object passed to expression evaluation
*/
interface ExpressionContext {
/** The current field configuration */
field: FormlyFieldConfig;
/** The form model data */
model: any;
/** The current form state */
formState: any;
/** The form options */
options: FormlyFormOptions;
}
/**
* Result of expression evaluation
*/
interface ExpressionResult<T = any> {
/** The evaluated value */
value: T;
/** Whether the value has changed since last evaluation */
changed: boolean;
}These functions are marked with the ɵ prefix and are intended for internal use by the library.
/**
* Internal function for defining hidden properties
* @internal
*/
function ɵdefineHiddenProp(field: any, prop: string, defaultValue: any): void;
/**
* Internal function for reverse deep merge operations
* @internal
*/
function ɵreverseDeepMerge(dest: any, ...args: any[]): any;
/**
* Internal function for getting field values
* @internal
*/
function ɵgetFieldValue(field: FormlyFieldConfig): any;
/**
* Internal function for cloning values
* @internal
*/
function ɵclone(value: any): any;
/**
* Internal function for creating observables
* @internal
*/
function ɵobserve<T>(
field: FormlyFieldConfig,
expression: FieldExpression<T>,
defaultValue?: T
): Observable<T>;
/**
* Internal function for checking if field has a key
* @internal
*/
function ɵhasKey(field: FormlyFieldConfig): boolean;import { observe, FormlyFieldConfig } from '@ngx-formly/core';
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
class CustomExpressionEvaluator {
evaluateConditionalVisibility(field: FormlyFieldConfig): Observable<boolean> {
const modelObservable = observe(field, 'model', {});
const formStateObservable = observe(field, 'formState', {});
return combineLatest([modelObservable, formStateObservable]).pipe(
map(([model, formState]) => {
// Complex visibility logic
return model.showAdvanced && formState.userLevel === 'expert';
})
);
}
}import { reverseDeepMerge, clone } from '@ngx-formly/core';
class FieldConfigurationManager {
mergeConfigurations(
baseConfig: FormlyFieldConfig,
...overrides: Partial<FormlyFieldConfig>[]
): FormlyFieldConfig {
// Clone base configuration to avoid mutations
const clonedBase = clone(baseConfig);
// Merge all overrides
return reverseDeepMerge(clonedBase, ...overrides);
}
createVariant(
baseConfig: FormlyFieldConfig,
variant: 'readonly' | 'required' | 'hidden'
): FormlyFieldConfig {
const variants = {
readonly: { props: { readonly: true } },
required: { props: { required: true } },
hidden: { hide: true }
};
return this.mergeConfigurations(baseConfig, variants[variant]);
}
}