JSPM

  • Created
  • Published
  • Downloads 102
  • Score
    100M100P100Q74601F
  • License MIT

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

Package Exports

  • ngx-dynamic-form-builder

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ngx-dynamic-form-builder) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Greenkeeper badge Build Status npm version

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

Installation

npm i --save ngx-dynamic-form-builder

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

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

Usage

app.module.ts

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

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

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);
    }
}

company-panel.component.html

<form [formGroup]="form" novalidate>
    <input formControlName="name" placeholder="Name">
    <p *ngIf="form?.formErrors?.name?.length">
      Error: {{form.formErrors.name[0]}}
    </p>
    <p>Form status: {{ form.status | json }}</p>
    <p *ngIf="!form.valid">
      Form errors: {{form?.formErrors|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>

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 {
  @Input()
  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 {
    if (this.form.valid) {
      this.savedItem = this.form.object;
    } else {
      this.form.validateAllFormFields();
    }
  }
}

custom-validators.ts

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

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

Observable Errors

the customValidateErrors property can be subscribed for cases in which your code should act on changes in errors

company-panel.component.html

<form [formGroup]="form" novalidate>
    <input formControlName="name" placeholder="Name">
    <p *ngIf="(form?.customValidateErrors | async)?.name?.length">
      Error: {{(form.customValidateErrors | async).name[0]}}
    </p>
    <p>Form status: {{ form.status | json }}</p>
    <p *ngIf="!form.valid">
      Observable validation errors: {{form.customValidateErrors|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>

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';
import { Subscription } from 'rxjs';

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

  @Input()
  form: DynamicFormGroup<Company>;
  @Input()
  item = new Company({
    'id': 11,
    'name': '123456789012345'
  });
  @Input()
  strings = Company.strings;

  fb = new DynamicFormBuilder();
  savedItem: Company;

  errorChangeSubscription: Subscription;

  constructor() {
    this.form = this.fb.group(Company, {
      name: ''
    });

    this.errorChangeSubscription = this.form.customValidateErrors.subscribe((allErrors) => {
      console.log('Errors changed': allErrors);
    })
  }
  ngOnDestroy() {
    if(this.errorChangeSubscription != null && this.errorChangeSubscription.closed === false) {
      this.errorChangeSubscription.unsubscribe();
    }
  }
  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 {
    if (this.form.valid) {
      this.savedItem = this.form.object;
    } else {
      this.form.validateAllFormFields();
    }
  }
}

License

MIT