4

i m generating form from json file with help of reactive forms.Generation of form works properly but the problem i m facing is - when i click on checkbox for first time in mozila its value becomes "on". but when i uncheck it nothing is happening its value remains "On" which should be "off or false". In chrome on click nothing is happening.

app.components.ts

import { Component } from '@angular/core';
import { QuestionControlService } from './question-control.service';
import GxData from './gx.json';
@Component({
  selector: 'app-root',
  template: `
    <div>
      <app-dynamic-form [questions]="questions"></app-dynamic-form>
    </div>
  `,
  providers: []
})
export class AppComponent{

  questions: any[];
  constructor() {
    this.questions = GxData;
  }

} 

dynamic-form.components.ts

import { Component, Input, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionControlService } from '../question-control.service';
import SbbData from '../sbb.json';
import GxData from '../gx.json';

@Component({
  selector: 'app-dynamic-form',
  templateUrl: './dynamic-form.component.html',
  providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {

  @Input() questions: any[] = [];
  form: FormGroup;
  payLoad = '';

  constructor(private qcs: QuestionControlService) { }

  ngOnInit() {
    this.form = this.qcs.toFormGroup(this.questions);
  }
  callGx() {
    this.questions = GxData;
    this.form = this.qcs.toFormGroup(this.questions);
  }
  callSbb() {
    this.questions = SbbData;
    this.form = this.qcs.toFormGroup(this.questions);
  }

  onSubmit() {

    this.payLoad = JSON.stringify(this.form.value);
    console.log(JSON.parse(this.payLoad));
  }

}

dynamic-form.component.html

<div class="search_box">
  <form (ngSubmit)="onSubmit()" [formGroup]="form">
      <button type="button" (click)="callSbb()">SBB</button> 
      <button type="button" (click)="callGx()">GX</button> 
    <div *ngFor="let question of questions" class="form-row">
      <app-question [question]="question" [form]="form"></app-question>
    </div>

    <div class="form-row">
      <button type="submit" [disabled]="!form.valid">Save</button>
    </div>
  </form>

  <div *ngIf="payLoad" class="form-row">
    <strong>Saved the following values</strong><br>{{payLoad}}
  </div>
</div>
{{form.value |json}} 

question-control.service.ts

import { Injectable } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Injectable()
export class QuestionControlService {
  constructor() { }

  toFormGroup(questions: any[]) {
    let group: any = {};

    questions.forEach(question => {
      group[question.key] = question.required ? new FormControl(question.value || '', Validators.required)
        : new FormControl(question.value || '');
    });
    return new FormGroup(group);
  }
}

dynamic-form-question.component.ts

import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';

// import { QuestionBase } from '../question-base';

@Component({
  selector: 'app-question',
  templateUrl: './dynamic-form-question.component.html'
})
export class DynamicFormQuestionComponent {
  @Input() question: any;
  @Input() form: FormGroup;
  get isValid() { return this.form.controls[this.question.key].valid; }
}

dynamic-form-question.component.html

<div [formGroup]="form">


  <div [ngSwitch]="question.controlType" class="checkbox_wrapper">

    <input *ngSwitchCase="'textbox'" [formControlName]="question.key" [id]="question.key" [type]="question.type" name="{{question.name}}">
    <label [attr.for]="question.key">{{question.label}}</label>

    <select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key" name = "{{question.name}}" >
      <option *ngFor="let opt of question.options" [attr.value]="opt.key" [selected]="opt.select">{{opt.value}}</option>
    </select>
  </div>
  <div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div> 

both json-files look like

[
    {
        "key": "Context",
        "label": "Context",
        "required": false,
        "order": 1,
        "controlType": "textbox",
        "name": "Context",
        "type": "checkbox"
    },
    {
        "key": "contextopt",
        "label": "",
        "required": false,
        "order": 2,
        "controlType": "dropdown",
        "name": "contextopt",
        "options": [
            {
                "key": "All Context",
                "value": "All Context",
                "select": true
            },
            {
                "key": "aaa",
                "value": "aaa"
            },
            {
                "key": "bb",
                "value": "bb"
            },
            {
                "key": "Other",
                "value": "Other"
            }
        ]
    },
    {
        "key": "Movement",
        "label": "Movement",
        "required": false,
        "order": 3,
        "controlType": "textbox",
        "name": "Movement",
        "type": "checkbox"
    }
]
2
  • i don't see a checkbox in dynamic-form-question.component.html? Commented Jun 27, 2019 at 14:09
  • @ysf [type] = question.type decides it will be checkbox or something else. <input *ngSwitchCase="'textbox'" [formControlName]="question.key" [id]="question.key" [type]="question.type" name="{{question.name}}"> . its generated from json file. Commented Jun 27, 2019 at 14:13

1 Answer 1

4

Update the problem is when you write [type]="question.type" and question.type="checkbox". It's look like Angular not love this for checkbox, (but love if use email, number....)

Replace the ng*SwitchCase="'textbox'" for

<ng-container *ngSwitchCase="'textbox'">
<input  *ngIf="question.type!='checkbox'" [formControlName]="question.key"
        [id]="question.key" [type]="question.type">
<input *ngIf="question.type=='checkbox'" [formControlName]="question.key"
        [id]="question.key" type="checkbox">
</ng-container>

You can be the example in stackblitz

Other Idea is create a new type, "checkbox" and a new option of switchCase The new CheckBoxQuestion is copy of textbox

export class CheckBoxQuestion extends QuestionBase<boolean> {
  controlType = 'checkbox';

  constructor(options: {} = {}) {
    super(options);
  }
}

And the switchCase add

<input *ngSwitchCase="'checkbox'" type="checkbox" [formControlName]="question.key">

, in the stackblitz you has the two cases

NOTE: You're creating a large loop of

<div [formGroup]="form">
   <input formGroupName="question.key">
</div>
<div [formGroup]="form">
   <input formGroupName="question.key">
</div>
   ...

I suggest, change your dynamic-form-question.component.html to create simply

<div>
  <input [formControl]="form.get(question.key)" ..>
</div>

Yes, change the combination [formGroup]="form"..formControlName=".." by [formControl]="form.get(..").

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

6 Comments

Has you see an error in console? (the strange is that a checkbox has value true/false -never ON, off or another)
i was seeing error for dropdown but then i commented that code. code rendered all the checkboxes properly but problem was same. Moreover in Google Chrome nothing happens not even "on"
Updated my answer. The solution is , in ng-container check if type is checkbox or not, if is checkbox, directily write type="checkbox", else [type]="question.type"
Great! thanks, It worked perfectly. but Can you explain why it was happening?. type was checkbox before as well.
Life saver. How is there no issue on angular github?
|

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.