8

I'm facing an issue with an existing application, below is my scenario I'm having the below JSON format

.html code

<div class="panel-group" id="accordion">
    <div *ngFor="let property of Tree.properties">
      <div class="panel panel-default">
        <div class="panel-heading">
          <h4 class="panel-title">
            <a class="link" data-toggle="collapse" data-parent="#accordion" href="#dataCatg-{{property.name}}">
              <div *ngIf="property.required">
                <span class="glyphicon glyphicon-chevron-right"></span>{{property.name}}
              </div>
              <div *ngIf="!property.required">
                <span class="glyphicon glyphicon-chevron-right"></span>{{property.name}}
              </div>
            </a>
          </h4>
        </div>
        <div id="dataCatg-{{property.name}}" class="panel-collapse collapse">
          <div class="panel-body">
            <ul class="list-group">
              <li class="list-group-item" *ngFor="let prop of property.details">
                <div *ngIf="prop.details.visible">
                  <div class="row">
                    <div class="col-md-4">
                      <div *ngIf="data.includes(prop.name)">
                        <label class="inline-label" for="{{prop.name}}">{{prop.name}}</label>
                      </div>
                      <div *ngIf="!data.includes(prop.name) ">
                        <label class="inline-label " for="{{prop.name}} ">{{prop.name}}</label>
                      </div>
                    </div>
                  <div class="col-md-8 ">
                      <div *ngIf="!Edit">
                        <span *ngIf="formVisible && metaDataTemplateMap[selectedFile]!==undefined ">
                          <input id="{{prop.name}}" type="{{prop.details.type}} " [(ngModel)]="Data[prop.name]" class="form-control ">
                        </span>
                      </div>
                      <div *ngIf="Edit">
                        <div *ngIf="prop.details.group ">
                          <span *ngIf="formView">
                            <!--need-->
                            <input id="{{prop.name}}" type="{{prop.details.type}}" [(ngModel)]="Edit[prop.name]" (ngModelChange)="Edit($event)" style=" border-radius:0;"
                             class="form-control">
                          </span>
                        </div>
                        <div *ngIf="!prop.details.group ">
                          <input id="{{prop.name}}" type="text " style=" border-radius:0" class="form-control " readonly>
                        </div>
                     </div>
                    </div>
                  </div>
                </div>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>

.ts Code

Data(res) {


    this.Tree['Properties'] = [];

    for (let property in res.properties) {

      var prop = res.properties[property];
      if (prop['properties'] !== undefined) {
        let temp= {};
        if (res['required'].indexOf(property) !== -1) {
          temp['required'] = true;
        }
        else {
          temp['required'] = false;
        }
        temp['name'] = property;
        let template = {};
        temp['details'] = [];
        for (let nestedProps in prop.properties) {
          let nestedProp = {};
          nestedProp['name'] = nestedProps;

          if (prop.properties[nestedProps]['type'] == 'string' || prop.properties[nestedProps]['type'] == 'date-time') {
            prop.properties[nestedProps]['type'] = 'text';
            template[nestedProps] = '';
          }

          if (prop.properties[nestedProps]['type'] == 'integer') {
            prop.properties[nestedProps]['type'] = 'number';
            template[nestedProps] = 0;
          }

          if (prop.properties[nestedProps]['type'] == 'array') {
            prop.properties[nestedProps]['type'] = 'array';
            template[nestedProps] = '';
          }
          if (prop.properties[nestedProps]['group'] == true) {
            if (this.Edit[property] == undefined)
              this.Edit[property] = {};
            this.Edit[property][nestedProps] = '';
          }

          nestedProp['details'] = prop.properties[nestedProps];

          temp['details'].push(nestedProp);
        }
        this.Data[property] = template;
        this.Tree['Properties'].push(temp);
      }
      if (prop['properties'] == undefined) {
        let temp = {};
        if (res['required'].indexOf(property) !== -1) {
          temp['required'] = true;
        }
        else {
          temp['required'] = false;
        }
        temp['name'] = property;
        if (prop['type'] == 'string' || prop['type'] == 'date-time') {
          prop['type'] = 'text';
          this.Data[property] = '';
        }

        if (prop['type'] == 'number') {
          prop['type'] = 'integer';
          this.Data[property] = 0;
        }

        if (prop['group'] == true) {
          this.Edit[property] = '';
        }
        temp['details'] = prop;
        this.Tree['Others'].push(temp);
      }
    }


  }

here what I'm want is 1. if You see in the JSON I have

"required": [
    "host", 
    "quantity", 
    "id"
], 

while generating the fields it has to check the above mentioned fields are empty or not with out template or reactive form approach how can it be possible if the fields are empty then we have let user know that fields are empty how can I accomplish this ?

9
  • 1
    is there a particular reason why you don't want to use reactive forms? Also what do you mean by "let user know that fields are empty" do you want to display something? Commented Oct 24, 2018 at 13:28
  • 1
    Would you please give an example or dummy data of your json Tree and Edit. or create running example on stackblitz. Commented Oct 24, 2018 at 13:31
  • @YoukouleleY this is an existing application which already developed with out that if i want to build that in reactive forms then it may take some time and i wan t to display an alert if the give fields in array are empty Commented Oct 25, 2018 at 4:07
  • @Nour i will update it shortly.. Commented Oct 25, 2018 at 4:07
  • I would say that this is in dire need of a refactor, and that you should convert it to reactive forms to save yourself inevitable future pain! Commented Oct 26, 2018 at 15:40

1 Answer 1

5
+50

Aim

Validation of dynamic generated form input without Reactive or Template Approach.

Solution

Directive will be best use for such kind of requirement. Directive helps to break the complicated job into small independent task. Lets see how it can be implemented.

Implementation provided below doesn't require any change in your existing code.

1. Validate Service

import { Injectable } from '@angular/core';

@Injectable()
export class ValidateService {

  errors = {};

  validate(key: string, value: object) {
    this.errors[key] = value;
  }

  getErrors() {
    let errorList = [];
    Object.keys(this.errors).forEach(key => {
      let value = this.errors[key];
      if ((value == undefined || value == '')  && this.required.find(item=>item == key)) {
        errorList.push({ name: key, error: key + " Field is required" })
      }
    });
    return errorList;
  }

   //All required fields can be maintained here
  required = [
    "host",
    "quantity",
    "id"
  ]

}

2. Validate Directive

ValidateDirective is responsible to collect the current value of input control if any change happens. This information will be passed to the service class ValidationService.

import { Directive, Host, Input, OnChanges, SimpleChanges, ViewContainerRef, AfterViewInit } from '@angular/core';
import { ValidateService } from './validate.service';

@Directive({
  selector: '[validate]'
})
export class ValidateDirective implements OnChanges {

  constructor(private service: ValidateService, private containerRef: ViewContainerRef) {

  }

  @Input("ngModel") model;

  @Input("validate") element;

  ngOnChanges(changes: SimpleChanges) {

    setTimeout(() => {
      this.service.validate(this.containerRef.element.nativeElement.id, changes.model.currentValue);
    })
  }

}

3. Directive Usage

ValidateDirective can be used with any input controls which has id and ngModel.

ex:

<input [validate] id="{{prop.name}}" type="{{prop.details.type}}" [(ngModel)]="Edit[prop.name]" (ngModelChange)="Edit($event)" style=" border-radius:0;" class="form-control">

4. Component ts

ValidateService will be Injected into component to get the list of errors.

constructor(private service:ValidateService) {}

  public get errors(){
    return this.service.getErrors();
  }

5. Displaying errors

Since all errors are available in Component, it can be displayed in the html.

ex :

 <li *ngFor="let error of errors">
     {{error.error}}
 </li>  

Note - There are many thing which can be enhanced further like

  1. Passing custom message to Directive.
  2. Required field list can be passed to Directive as @Input

Working sample demo is here - https://stackblitz.com/edit/angular-xnbzqd

Sign up to request clarification or add additional context in comments.

9 Comments

ok but in the service.ts u have maintained the required fields in static way but i am getting those via json schema & how to can display these dynamic fields name in alert i mean what ever required fields is not empty can i show it in alert
Since this in service class, we can create the setter for the required list and this can be set from the Component or any other class. I have updated the demo as well.
i mean i have a dropdown and based on the the value the various json schema's are being loaded so in that case also it is possible ?
yes, you just need to pass it to service class. that's all.
ok and how can i get the field name so that i can show that in alert suppose at first user doest fill 3 mandatory fields they user will get alert too as these fields are not filled after user out of 3 fields user enter 2 fields and 1 fields left and again it will show alert that particular field is not filled
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.