mat-dynamic-form

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.

Usage no npm install needed!

<script type="module">
  import matDynamicForm from 'https://cdn.skypack.dev/mat-dynamic-form';
</script>

README

GitHub Workflow Status npm (tag) npm bundle size

Mat Dynamic Form

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.

Installation


npm i mat-dynamic-form

Dependencies

Angular Material

Angular Material Documentation


ng add @angular/material

This is necesary to create angular material components.

Usage

AppModule


import { NgModule } from '@angular/core';
import { MatDynamicFormModule } from 'mat-dynamic-form';

@NgModule({
  imports: [
    ...,
    MatDynamicFormModule
  ],
  providers: [],
  ...
})

export class AppModule {}

HTML


<mat-dynamic-form  [structure]="formStructure"></mat-dynamic-form>

TS

This is an example of a full sing up form.


import { Component, OnInit } from '@angular/core';
import { Validators } from '@angular/forms';
import { Button, Checkbox, DatePicker, Dropdown, FormListener, FormStructure, Input, InputFile, InputPassword, OptionChild, RadioGroup, TextArea } from 'projects/mat-dynamic-form/src/public-api';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, FormListener {

  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'
      }),
      new Button('find', 'Find', { callback: this, 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: 'change', callback: this }
      }),
      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', {
        callback: this, style: 'warn'
      }).apply({
        icon: 'close'
      }),
      new Button('save', 'Save', {
        callback: this, style: 'primary',
      }).apply({
        validateForm: true,
        icon: 'save'
      }),
    ];
  }

  ngOnInit(): void {
  }

  onEvent(id: string, value: any): void {
    if (id == 'hasPet') {
      console.log(id)
      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 (value == 'y') {
        this.formStructure.createNodes(7, nodes)
      } else this.formStructure.removeNodes(nodes)
    }
  }

  onClick(actionId: string): void {
    switch (actionId) {
      case 'save':
        this.formStructure?.pathValue({ name: 'Carlos', hasPet: 'y' });
        break;
      case 'cancel':
        console.log(this.formStructure)
        this.formStructure?.reset();
        this.formStructure?.remapValues();
        break;
    }
  }
}

Custom Component (TS)

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() {
  }
}

Custom Component (HTML)

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>
...

Resulting Form

image

Node Types

Classes

Apply Method

ObjectBase.apply

Usage


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).