Dynamic Nodes
Mat Dynamic Form allows you to add and remove form fields dynamically at runtime based on user interactions or application state. This is useful for conditional forms, wizards, and multi-step processes.
Core Methods
createNodes()
Adds multiple nodes to the form at a specific position.
createNodes(from: number, nodes: Node[]): void
Parameters:
from - The index position where nodes will be inserted
nodes - Array of Node instances to add
Example:
import { FormStructure, Input, Dropdown, OptionChild } from 'mat-dynamic-form';
const formStructure = new FormStructure();
// Add nodes at position 5
const newNodes = [
new Input('email', 'Email Address'),
new Dropdown('country', 'Country', [
new OptionChild('United States', 'US'),
new OptionChild('Canada', 'CA')
])
];
formStructure.createNodes(5, newNodes);
See FormStructure.ts:232 for implementation details.
removeNodes()
Removes multiple nodes from the form.
removeNodes(nodes: Node[]): void
Parameters:
nodes - Array of Node instances to remove
Example:
// Remove previously added nodes
formStructure.removeNodes(newNodes);
See FormStructure.ts:243 for implementation details.
When removing nodes, make sure to pass the same node instances that were added. The removal is based on node IDs, so nodes with matching IDs will be removed from both the form structure and the FormGroup.
A common use case is showing/hiding fields based on another field’s value using the valueChange event.
Create the trigger field
Add a field that will trigger the dynamic behavior:new RadioGroup('hasPet', 'Has Pet', [
new OptionChild('Yes', 'y'),
new OptionChild('Not', 'n'),
]).apply({
selectedValue: 'n',
action: {
type: 'valueChange',
onEvent: (param) => this.onHasPetValueChange(param)
}
})
Define the conditional nodes
Create the nodes that will be added/removed:onHasPetValueChange(param: ActionEvent) {
const petNodes = [
new Dropdown('petType', 'Pet Type', [
new OptionChild('Dog', 'PD'),
new OptionChild('Cat', 'PC')
]),
new Input('breed', 'Pet Breed'),
new Input('petName', 'Pet Name')
];
if (param.event == 'y') {
// Add nodes at position 7
this.formStructure.createNodes(7, petNodes);
} else {
// Remove nodes when not needed
this.formStructure.removeNodes(petNodes);
}
}
Handle form submission
When getting form values, only the currently visible nodes will be included:const formValues = this.formStructure.getValue();
// petType, breed, and petName only present if hasPet === 'y'
See README.md:166-178 for a complete example.
Dynamic Validate Actions
createValidateActions()
You can also dynamically add action buttons to the form.
createValidateActions(from: number, nodes: Button[]): void
Example:
import { Button } from 'mat-dynamic-form';
const saveButton = new Button('save', 'Save', {
onEvent: (param) => {
const values = param.structure.getValue();
console.log(values);
},
style: 'primary'
}).apply({
validateForm: true,
icon: 'save'
});
formStructure.createValidateActions(0, [saveButton]);
See FormStructure.ts:255 for implementation details.
removeValidateActions()
Removes action buttons from the form.
removeValidateActions(nodes: Button[]): void
Example:
formStructure.removeValidateActions([saveButton]);
Dynamic validate actions are useful for wizard-style forms where different steps require different action buttons (Next, Previous, Submit, etc.).
Advanced Patterns
Cascading Dropdowns
Create dropdowns where the options in one depend on the selection in another:
new Dropdown('state', 'State', stateOptions).apply({
action: {
type: 'valueChange',
onEvent: (param) => {
const stateCode = param.event;
// Remove old city dropdown if exists
const cityNode = new Dropdown('city', 'City', []);
this.formStructure.removeNodes([cityNode]);
// Load cities for selected state
const cities = this.getCitiesForState(stateCode);
const newCityNode = new Dropdown('city', 'City', cities);
// Add new city dropdown after state field
this.formStructure.createNodes(param.structure.nodes.length, [newCityNode]);
}
}
})
Implement wizard-style forms by dynamically swapping entire sections:
goToStep(stepNumber: number) {
// Remove all current nodes
this.formStructure.removeNodes(this.currentStepNodes);
// Add nodes for new step
const newStepNodes = this.getNodesForStep(stepNumber);
this.formStructure.createNodes(0, newStepNodes);
// Update current step tracking
this.currentStepNodes = newStepNodes;
this.currentStep = stepNumber;
}
When dynamically adding nodes with validators, ensure that the form validation state is updated. You can call param.structure.getFormGroup().updateValueAndValidity() to recalculate the form’s validation status.
Best Practices
- Store Node References: Keep references to dynamically created nodes if you need to remove them later
- Position Carefully: Consider the visual flow when choosing insertion positions
- Clean Up: Always remove nodes that are no longer needed to keep the form clean
- Validate After Changes: Check form validity after adding/removing nodes with validators
- Preserve User Data: When removing and re-adding nodes, consider storing user input to restore later