Overview
The FormStructure class is the core container for your dynamic form. It manages nodes, handles validation, provides form data access, and controls the overall form behavior.
import { FormStructure, Input, Button } from 'mat-dynamic-form';
import { Validators } from '@angular/forms';
const formStructure = new FormStructure(
'Sign Up', // title
[], // nodes (can be added later)
[] // validate actions (optional)
);
Core Properties
The title displayed at the top of the form
Array of form nodes (inputs, dropdowns, checkboxes, etc.) - see Nodes
Action buttons displayed at the bottom of the form (max 4 allowed)
Number of columns in the grid layout (1-4). Controls how nodes are arranged horizontally.
appearance
MatFormFieldAppearance
default:"'standard'"
Material Design appearance style: 'standard', 'fill', or 'outline'
Whether to display the form title
globalValidators
ValidatorFn | ValidatorFn[] | null
Validators applied to all form fields - see Validators
Whether to validate disabled fields
Maximum height of the form container
When true, only the form content scrolls while title and actions remain fixed
getValue()
Returns the current form values as a typed object. Disabled fields are excluded.
interface UserData {
name: string;
email: string;
subscribe: boolean;
}
const data = formStructure.getValue<UserData>();
console.log(data);
// { name: 'John Doe', email: '[email protected]', subscribe: true }
getRawValue()
Returns form values including disabled fields.
const allData = formStructure.getRawValue<UserData>();
// Includes values from disabled fields
Use getRawValue() when you need to access values from disabled fields, such as when pre-populating forms in edit mode.
patchValue()
Updates specific form field values without affecting other fields.
patchValue() throws a ReferenceException if you try to set a value for a non-existent control ID.
reset()
Resets all form fields to their initial values.
remapValues()
Resets all fields to their default values as defined in the node configuration.
formStructure.reset();
formStructure.remapValues(); // Restore original default values
Validation
isValid()
Checks if the entire form is valid.
if (formStructure.isValid()) {
console.log('Form is valid!');
}
isInvalid()
Checks if the form has any validation errors.
if (formStructure.isInvalid()) {
console.log('Please fix form errors');
}
Dynamic Node Management
createNodes()
Adds nodes dynamically at a specific position.
const newNodes = [
new Input('address', 'Address'),
new Input('city', 'City')
];
// Insert at position 5
formStructure.createNodes(5, newNodes);
removeNodes()
Removes nodes from the form.
formStructure.removeNodes(newNodes);
When removing nodes, their form controls are automatically removed from the underlying FormGroup.
Practical Example: Conditional Fields
const hasPetRadio = new RadioGroup('hasPet', 'Do you have a pet?', [
new OptionChild('Yes', 'yes'),
new OptionChild('No', 'no')
]).apply({
action: {
type: 'valueChange',
onEvent: (param: ActionEvent) => {
const petDetailsNodes = [
new Input('petName', 'Pet Name'),
new Dropdown('petType', 'Pet Type', [
new OptionChild('Dog', 'dog'),
new OptionChild('Cat', 'cat')
])
];
if (param.event === 'yes') {
param.structure.createNodes(5, petDetailsNodes);
} else {
param.structure.removeNodes(petDetailsNodes);
}
}
}
});
getControlById()
Accesses the underlying Angular AbstractControl for a field.
const nameControl = formStructure.getControlById('name');
if (nameControl) {
nameControl.setValue('New Value');
nameControl.setErrors({ custom: 'Custom error' });
console.log(nameControl.valid);
}
getNodeById()
Retrieves a node instance by its ID.
const dateNode = formStructure.getNodeById<DatePicker>('startDate');
dateNode.minDate = new Date();
getActionById()
Retrieves a validate action button by its ID.
const saveButton = formStructure.getActionById('save');
console.log(saveButton.placeholder); // 'Save'
Accesses the underlying Angular FormGroup instance.
const formGroup = formStructure.getFormGroup();
if (formGroup) {
formGroup.valueChanges.subscribe(values => {
console.log('Form changed:', values);
});
}
setFromGroup()
Replaces the internal FormGroup with a new instance (advanced usage).
import { FormGroup } from '@angular/forms';
const customFormGroup = new FormGroup({});
formStructure.setFromGroup(customFormGroup);
This is an advanced method. In most cases, you won’t need to manually set the FormGroup.
Dynamic Validators
Add or update validators at runtime. See Validators for details.
addValidators()
formStructure.addValidators('email', Validators.email);
setValidator()
Replaces existing validators.
formStructure.setValidator('phone', [
Validators.required,
Validators.pattern(/^\d{10}$/)
]);
addAsyncValidators()
formStructure.addAsyncValidators('username', usernameAsyncValidator);
Complete Example
import { Component } from '@angular/core';
import { Validators } from '@angular/forms';
import {
FormStructure,
Input,
Checkbox,
Dropdown,
Button,
OptionChild
} from 'mat-dynamic-form';
@Component({
selector: 'app-user-form',
template: '<mat-dynamic-form [structure]="formStructure"></mat-dynamic-form>'
})
export class UserFormComponent {
formStructure: FormStructure;
constructor() {
this.formStructure = new FormStructure('User Registration');
// Configure appearance
this.formStructure.appearance = 'outline';
this.formStructure.nodeGrid = 2;
this.formStructure.globalValidators = Validators.required;
this.formStructure.onlyScrollContent = true;
// Add form nodes
this.formStructure.nodes = [
new Input('name', 'Full Name').apply({
icon: 'person',
maxCharCount: 100
}),
new Input('email', 'Email').apply({
icon: 'email',
validator: [Validators.required, Validators.email]
}),
new Dropdown('country', 'Country', [
new OptionChild('United States', 'us'),
new OptionChild('United Kingdom', 'uk'),
new OptionChild('Canada', 'ca')
]),
new Checkbox('subscribe', 'Subscribe to newsletter', false)
];
// Add action buttons
this.formStructure.validateActions = [
new Button('reset', 'Reset', {
style: 'warn',
onEvent: (param) => {
param.structure.reset();
param.structure.remapValues();
}
}).apply({ icon: 'refresh' }),
new Button('submit', 'Submit', {
style: 'primary',
onEvent: (param) => {
if (param.structure.isValid()) {
const data = param.structure.getValue();
console.log('Submitting:', data);
// Call API here
}
}
}).apply({
validateForm: true,
icon: 'check'
})
];
}
}
- Nodes - Learn about different form field types
- Actions - Handle form events and interactions
- Validators - Add validation rules to your forms