3

I am new at Angular and trying to make dynamic forms with JSON data. The conditions should be selected from the options type selection from the JSON data. I have tried the following code but it does not work

<mat-card class="rahmendaten-container">
  <h3 class="page__header">{{stepCfg.stepHeading}}</h3>
  <div *ngIf="!!stepCfg.htmlContent" [innerHTML]="stepCfg.htmlContent"> 
  </div>
  <form [formGroup]="form" autocomplete="off" (ngSubmit)="onSubmit()">
    <mat-card-content class="page">
      <div class="page__container">
        <div *ngFor="let prop of formTemplate" class="container__row">
          <div [ngSwitch]="prop.type">
            <div *ngSwitchCase="'select'">
              <span [innerHTML]="prop.label" 
              class="container__row__label"></span>
              <mat-form-field>
                <mat-select [formControlName]="onChange($event,prop)" 
                [formControlName]="values[prop.label + i]">
                  <mat-option *ngFor="let option of prop.options" 
                  [value]="option.value">{{option.label}}</mat-option>
                </mat-select>
              </mat-form-field>
            </div>
          </div>
        </div>
      </div>
    </mat-card-content>
  </form>
</mat-card>

Type script

import { Component, OnInit } from '@angular/core'; 
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { MatDialog, MatDialogRef } from '@angular/material';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
    form:FormGroup;
    array: any[] = [];
    selectItems: any;
    formTemplate:any = form_template;
    stepCfg = {
      stepType: 'rahmendaten',
      stepHeading: '',
      stepIndex: 0,
      steps: [],
      firstStep: false,
      lastStep: false,
      onlyStep: false,
      data: {},
      htmlContent: ''
    };
    formDataObj = {};

  constructor() {}   

  ngOnInit() {
    for (const prop of Object.keys(this.stepCfg.data)) {
      this.formDataObj[prop] = new 
      FormControl(this.stepCfg.data[prop].value);
      this.formTemplate.push({
        key: prop,
        label: this.stepCfg.data[prop].label,
        type: this.stepCfg.data[prop].type,
        options: this.stepCfg.data[prop].options
      });
   }
   this.form = new FormGroup(this.formDataObj);
  }

  onChange(evt) {

    this.formTemplate.forEach(prop => {
      let options = prop.options.filter(x => x.value == evt)[0]
      var allLabels: string[] = this.formTemplate.map(x => x.label)

      if (options) {
        if (options.subfield && 
        !allLabels.includes(options.subfield.label)) {
          let obj = { ...options.subfield }
          this.formTemplate.push(obj)
        }
      }
    })
  }
}

 const form_template = [{
  "type": "select",
  "label": "Test1",
  "options": [
  {
      "value": "sped1",
      "label": "A Test GmbH",
      "subfield": {
        "type": "select",
        "label": "Subfield1",
        "options": [
          {
            "value": "subfieldvalue1",
            "label": "101"
          },
          {
            "value": "subfieldvalue1",
            "label": "101"
          },
        ]
       }
  },
  {
      "value": "sped2",
      "label": "Test2 GmbH"
  },
  {
     "value": "sped3",
     "label": "test3"
  },
  ]
}

] export default form_template

After getting the valueable help from @AdritaSharma; I havr tried this but it do not work.

14
  • 1
    And what have your tried, and where are you facing an issue? Commented Sep 17, 2019 at 19:29
  • Have you went through the modified solution? Commented Sep 18, 2019 at 17:44
  • @AdritaSharma Thank you so much this is what i wants but can you please help me to remove this error. ERROR in src/app/app.component.ts(46,15): error TS2339: Property 'isChild' does not exist on type '{ "type": string; "label": string; "options": { "value": string; "label": string; }[]; }'. Commented Sep 18, 2019 at 19:01
  • isChild property has to be included in the hain.. try adding it, I will modify the demo at morning. Commented Sep 18, 2019 at 19:29
  • Check the modified demo. Commented Sep 19, 2019 at 6:11

2 Answers 2

1

Try like this:

<ng-container *ngFor="let item of form_template">
    <ng-container [ngSwitch]="item.type">
        <div *ngSwitchCase="'select'">
      {{item.label}}
            <select>
               <option *ngFor="let option of item.options" [value]="option.sped1">
                   {{option.label}}
               </option>
            </select>
        </div>
    </ng-container>
</ng-container>

Demo

To accomodate Subfield I made few changes:

Working Demo with Subfield

Template:

<ng-container *ngFor="let item of form_template">
    <ng-container [ngSwitch]="item.type">
        <div *ngSwitchCase="'select'">
            {{item.label}}
            <select (ngModelChange)="onChange($event,item.isChild)" [(ngModel)]="values[item.label + i]">
        <option *ngFor="let option of item.options" [value]="option.value">
          {{option.label}}
        </option>
        </select>
        </div>
    </ng-container>
</ng-container>

Typescript:

 onChange(evt, isChild?) {

    this.form_template.forEach(item => {
      let options = item.options.filter(x => x.value == evt)[0]
      var allLabels: string[] = this.form_template.map(x => x.label)

      if (options) {

        if (options.subfield && !allLabels.includes(options.subfield.label)) {
          Object.assign(options.subfield, {isChild:true});
          this.form_template.push(options.subfield)
        }
      } else {
        this.form_template.forEach((x, i) => {
          x.options.forEach(y => {
            if (y.value != evt) {

              this.form_template.forEach((item, itemIndex) => {

                if (item.options.indexOf(y)) {
                  if (!isChild) {
                    this.form_template.splice(itemIndex, 1)
                  }
                }
              })
            }
          })
        })
      }
    })
  }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @Adrita sharma I have worked as you told but the problem is after selecting parent options from drop down the sub field content should be appear on the form such as in this cas after selecting the the first element Adrian Speditions GmbH from drop down the child content of this elements "label": "Subfield1", and another drop down options should be appear on the form.
@Learner I made some changes for subfield, go through the demo and let me know if you are unable to understand any part.
1

Well simply put it might be possible but it is more time consuming than traditional methods. If you do that several things come into play like design, error messages etc it will become complicated than what you have in hand. I also had this idea (inspired by.net MVC) but it's not worth it.

Comments

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.