This is an Angular Material library that was created to make form designing easier and intuitive, you just need to send a json object to generate a fully functional form.
npm i mat-dynamic-form
Angular Material Documentation
ng add @angular/material
This is necesary to create angular material components.
import { NgModule } from '@angular/core';
import { MatDynamicFormModule } from 'mat-dynamic-form';
@NgModule({
imports: [
...,
MatDynamicFormModule
],
providers: [],
...
})
export class AppModule {}
<mat-dynamic-form [structure]="formStructure"></mat-dynamic-form>
This is an example of a full sing up form.
import { Component, OnInit } from '@angular/core';
import { Validators } from '@angular/forms';
import { ActionEvent, Button, Checkbox, CustomNode, DatePicker, Dropdown, FormStructure, Input, InputFile, InputPassword, OptionChild, RadioGroup, TextArea } from 'projects/mat-dynamic-form/src/public-api';
import { InputComponent } from './input/input.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
formStructure: FormStructure;
constructor() {
this.formStructure = new FormStructure();
this.formStructure.title = 'Sign Up';
this.formStructure.appearance = 'standard';
this.formStructure.globalValidators = Validators.required;
this.formStructure.nodes = [
new Input('name', 'Name').apply({
icon: 'person',
maxCharCount: 100
}),
new Button('find', 'Find', { style: 'primary' }).apply({
icon: "search",
singleLine: false
}),
new Input('tel', 'Phone Number').apply({
icon: 'phone'
}),
new DatePicker('bDate', 'BirthDate').apply({
action: { callback: this, type: 'change' }
}),
new Dropdown('cStatus', 'Civil Status', [
new OptionChild('Single', 'SI',),
new OptionChild('Maried', 'MR')
]).apply({
selectedValue: 'SI',
disabled: true
}),
new InputFile('profPic', 'Profile Picture').apply({
accept: '.png, .jpg, .jpeg'
}),
new RadioGroup('hasPet', 'Has Pet', [
new OptionChild('Yes', 'y'),
new OptionChild('Not', 'n'),
]).apply({
selectedValue: 'n',
action: { type: 'valueChange', onEvent: (param) => this.onHasPetValueChange(param) }
}),
new InputPassword('pass', 'Password'),
new TextArea('comments', 'Comments').apply({
singleLine: true,
validator: Validators.maxLength(100),
maxCharCount: 100
}),
new CustomNode<InputComponent>('custom1', InputComponent, { label: 'Custom 1', placeholder: 'Custom Placeholder 1' }),
new CustomNode<InputComponent>('custom2', InputComponent, { label: 'Custom 2', placeholder: 'Custom Placeholder 2' }),
new Checkbox(
'agreement',
`I have read and agree to the terms of DynamicForm License Agreement, <strong><a href='https://www.google.com'>Read the license here.<a </strong>`
).apply({
singleLine: true,
validator: Validators.requiredTrue
}),
new CustomNode<InputComponent>('custom3', InputComponent, { label: 'Custom 3', placeholder: 'Custom Placeholder 2' }),
];
this.formStructure.validateActions = [
new Button('cancel', 'Cancel', {
onEvent: (param) => {
param.structure?.reset();
param.structure?.remapValues();
}, style: 'warn'
}).apply({
icon: 'close'
}),
new Button('save', 'Save', {
onEvent: (param) => param.structure?.patchValue({ name: 'Carlos', hasPet: 'y' }), style: 'primary',
}).apply({
validateForm: true,
icon: 'save'
}),
];
}
ngOnInit(): void {
}
onHasPetValueChange(param: ActionEvent) {
const nodes = [
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') {
this.formStructure.createNodes(7, nodes)
} else this.formStructure.removeNodes(nodes)
}
}
This is an example of a custom componente ts child code.
@Component({
selector: 'app-input',
templateUrl: './input.component.html',
styleUrls: ['./input.component.scss']
})
export class InputComponent implements OnInit {
control: FormControl; // <-- You must have to add this property
constructor() { }
ngOnInit() {
}
}
This is an example of a custom componente html child code.
...
<mat-form-field class="col-12" appearance="fill">
<mat-label>{{label}}</mat-label>
<input type="email" matInput placeholder="{{placeholder}}" [formControl]="control"> <!-- You must have to bind control property with your custom component fields -->
</mat-form-field>
...
new TextArea('comments', 'Comments').apply({
// All the properties of the object you´re using "apply" method.
singleLine: true,
validator: Validators.maxLength(100),
maxCharCount: 100
}),
This method can be used in all classes of the lib (like kotlin apply).
You can run this library in a Docker container to avoid dependency conflicts (e.g., Angular 11 with Node 14) and isolate it from other Angular projects.
Make sure you're in the root folder of the repo:
docker build -t angular11-dev -f Dockerfile .
If you don’t have a
Dockerfile
yet, you can create one like this:
# Usa Node.js 14, compatible con Angular 11
FROM node:14
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Instala Angular CLI versión 11 de forma global
RUN npm install -g @angular/cli@11
# Copia los archivos de dependencias
COPY package*.json ./
# Instala las dependencias del proyecto
RUN npm install
# Copia el resto de archivos del proyecto
COPY . .
# Expone el puerto 4200 (Angular dev server)
EXPOSE 4200
# Comando por defecto (puede ser override en docker run)
CMD ["ng", "serve", "--host", "0.0.0.0"]
To serve the sandbox app locally (port 4200):
docker run -it --rm -v "$PWD":/app -w /app -p 4200:4200 --init angular11-dev ng serve --host 0.0.0.0
- Changes to your local source files will be reflected in the running Docker container automatically, because you're mounting the code with
-v "$PWD":/app
. - If you're using symlinks, make sure Git tracks them correctly (
core.symlinks=true
). - If other collaborators use the project, recommend them to run the symlink command once after cloning.