DEV Community

ILshat Khamitov
ILshat Khamitov

Posted on

1

Dynamic form group builder for Angular9+ (not the builder for controls)

FormBuilder + class-transformer + class-validator = dynamic form group builder for Angular9+

Installation

npm i --save ngx-dynamic-form-builder
Enter fullscreen mode Exit fullscreen mode

Usage

company.ts

import { Validate, IsNotEmpty } from 'class-validator';
import { plainToClassFromExist } from 'class-transformer';
import { TextLengthMore15 } from '../utils/custom-validators';

export class Company {
    id: number = undefined;
    @Validate(TextLengthMore15, {
        message: 'The company name must be longer than 15'
    })
    @IsNotEmpty()
    name: string = undefined;

    constructor(data?: any) {
        plainToClassFromExist(this, data);
    }
}
Enter fullscreen mode Exit fullscreen mode

app.module.ts

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CompanyPanelComponent } from './company-panel.component';

@NgModule({
  imports: [
    ...
    FormsModule,
    ReactiveFormsModule,
    ...
  ],
  declarations: [
    ...
    CompanyPanelComponent,
    ...
  ],
  ...
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

company-panel.component.html

<form [formGroup]="form" *ngIf="form?.customValidateErrors | async as errors" novalidate>
    <input formControlName="name" placeholder="Name">
    <p *ngIf="errors.name?.length">
      Error: {{errors.name[0]}}
    </p>
    <p>Form status: {{ form.status | json }}</p>
    <p>
      Form class-validator errors: {{errors|json}}
    </p>
    <p>
      Form native errors: {{form?.nativeValidateErrors|async|json}}
    </p>
    <p *ngIf="savedItem">
      Saved item: {{savedItem|json}}
    </p>
    <button (click)="onLoadClick()">Load</button>
    <button (click)="onClearClick()">Clear</button>
    <button (click)="onSaveClick()" [disabled]="!form.valid">Save</button>
</form>
Enter fullscreen mode Exit fullscreen mode

company-panel.component.ts

import { DynamicFormGroup, DynamicFormBuilder } from 'ngx-dynamic-form-builder';
import { Company } from './../../shared/models/company';
import { Input, Component } from '@angular/core';
import { Validators } from '@angular/forms';

@Component({
  selector: 'company-panel',
  templateUrl: './company-panel.component.html'
})
export class CompanyPanelComponent {

  form: DynamicFormGroup<Company>;

  @Input()
  item = new Company({
    'id': 11,
    'name': '123456789012345'
  });

  fb = new DynamicFormBuilder();

  savedItem: Company;

  constructor() {
    this.form = this.fb.group(Company, {
      name: ''
    });
  }
  onLoadClick(): void {
    this.savedItem = undefined;
    this.form.object = this.item;
    this.form.validateAllFormFields();
  }
  onClearClick(): void {
    this.savedItem = undefined;
    this.form.object = new Company();
    this.form.validateAllFormFields();
  }
  onSaveClick(): void {
    this.form.validateAllFormFields();
    if (this.form.valid) {
      this.savedItem = this.form.object;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

custom-validators.ts

import {
    ValidatorConstraintInterface, ValidatorConstraint
} from 'class-validator';

@ValidatorConstraint()
export class TextLengthMore15 implements ValidatorConstraintInterface {
    validate(text: string) {
        return text ? text.length > 15 : false;
    }
}
Enter fullscreen mode Exit fullscreen mode

Links

Demo - Demo application with ngx-dynamic-form-builder.

Stackblitz - Simply sample of usage on https://stackblitz.com

Image of Docusign

Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs