Created
February 25, 2018 17:27
-
-
Save mustafamagdy/6a5098b5d8aaa4bcf267b0d7d39d514c to your computer and use it in GitHub Desktop.
Service to generate model driven forms for ReactiveForms in angular from JSON structure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Injectable } from '@angular/core'; | |
| import { Validators, ValidatorFn, FormGroup, FormControl, AbstractControl } from '@angular/forms'; | |
| @Injectable() | |
| export class ReactiveFormGeneratorService { | |
| constructor() { } | |
| /** | |
| * | |
| * @param model Json model in the following format | |
| * | |
| { | |
| "name": "User", | |
| "properties": { | |
| "firstName": { | |
| "type": "string", | |
| "validators": ["required", "maxLength(100)"] | |
| }, | |
| "lastName": { | |
| "type": "string", | |
| "validators": ["required", "maxLength(100)"] | |
| }, | |
| "email": { | |
| "type": "string", | |
| "validators": ["email", "minLength(10)", "maxLength(100)"] | |
| }, | |
| "address": { | |
| "street": { | |
| "type": "string", | |
| "validators": [] | |
| }, | |
| "zip": { | |
| "type": "number", | |
| "validators": [] | |
| } | |
| } | |
| } | |
| } | |
| * Useage: | |
| * this.form = new FormGroup(parseModel(....)); | |
| */ | |
| parseModel(model: any): { [key: string]: AbstractControl } { | |
| let properties = Object.entries(model.properties); | |
| let fields: { [key: string]: AbstractControl } = {}; | |
| type property = { type: string, validators: [string] }; | |
| fields = this.parseTree(properties, fields); | |
| return fields; | |
| } | |
| parseTree(properties: [string, {}][], fields: { [key: string]: AbstractControl }): { [key: string]: AbstractControl } { | |
| properties.reduce((result, p, index) => { | |
| if (p && p.length) { | |
| let field = (p[1] as { type: string, validators: [string] }); | |
| if (field && typeof field.type === 'string' && field.validators instanceof Array) { | |
| result[p[0]] = new FormControl('', this.parseValidators(field.type, field.validators)); | |
| } | |
| else { | |
| let gValidator = ''; | |
| let ar = Object.keys(p[1]).map(x => { | |
| if (x == 'validator') | |
| gValidator = p[1][x]; | |
| else | |
| return [x, p[1][x]]; | |
| }); | |
| let gp = this.parseTree(ar as [string, {}][], {}); | |
| result[p[0]] = new FormGroup(gp);//, gValidator); | |
| } | |
| return fields; | |
| } | |
| }, fields); | |
| return fields; | |
| } | |
| parseValidators(type: string, validators: [string]): ValidatorFn | ValidatorFn[] | null { | |
| //if no validator sipploed, return null | |
| if (!validators || !validators.length) return null; | |
| //check if validator is supported for type | |
| //this.validateValidValidators(type, validators); | |
| let result = validators.map(v => { | |
| let validatorAndParams = this.trimValidator(v); | |
| if (validatorAndParams.args && validatorAndParams.args.length) { | |
| return Validators[validatorAndParams.validtaor](validatorAndParams.args); | |
| } | |
| else { | |
| return Validators[validatorAndParams.validtaor]; | |
| } | |
| }); | |
| return result; | |
| } | |
| private validateValidValidators(type: string, validators: [string]) { | |
| //type's supported validations | |
| let validValidations = [ | |
| "string", ["required", "maxLength", "minLength", "email", "pattern"], | |
| "number", ["required", "min", "max"], | |
| "boolean", ["requiredTrue"], | |
| ] | |
| let validValidationsForType = validValidations[type]; | |
| let inValidValidator = ''; | |
| if (validators.some(v => { | |
| let notFound = validValidationsForType.indexOf(this.trimValidator(v).validtaor) == -1; | |
| if (notFound) | |
| inValidValidator = v; | |
| return notFound; | |
| })) { | |
| throw `Validator ${inValidValidator} not supported for type ${type}`; | |
| } | |
| } | |
| //shove off the validator and extract its parameters if exist | |
| private trimValidator(validator: string): { validtaor: string, args: any[] } { | |
| let splitter = new RegExp(/[(,)]/) | |
| let parts = validator.split(splitter).filter(a => a.trim() != ''); | |
| let validatorFun = parts[0]; | |
| let args = parts.slice(1); | |
| return { validtaor: validatorFun, args: args }; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment