title: creating checkbox with Dynamic forms in Angular 8
body: <p>Hi I am building a dynamic form in Angular 8. So far everything is working fine, but I have trouble implementing a checkbox control. The checkbox control shows up, and I try to see if it is checked or not.</p>
  
  <p>If it is set to true, in meta.json file, and I click it on the webpage, then the value becomes "true". I would expect false. If the value is false in meta.json, then there is no change on webpage when I click.</p>
  
  <p>meta.json</p>
  
  <pre><code>[ 
    [
      {
        "questionType": "dropdown",
        "key": "brave",
        "label": "Bravery Rating",
        "options": [
          {"key": "solid", "value": "Solid"},
          {"key": "great", "value": "Great", "selected": "selected"},
          {"key": "good", "value": "Good"},
          {"key": "unproven", "value": "Unproven"}
        ],
        "order": 3,
        "visibility": true
      },
      {
        "questionType": "checkbox",
        "key": "mycheck01",
        "label": "Mycheck01",
        "value": true,
        "type": "checkbox",
        "validators": [],
        "order": 2,
        "visibility": true
      },
      {
        "questionType": "textbox",
        "key": "firstName",
        "label": "First name",
        "value": "abcd",
        "type": "text",
        "validators": ["required"],
        "order": 2,
        "visibility": true
      },
      {
        "questionType": "textbox",
        "key": "emailAddress",
        "label": "Email",
        "value": "asd@ad.com",
        "type": "email",
        "order": 1,
        "validators": ["required", "email"],
        "visibility": "this.form.get('firstName').value === 'abc'"
      }
    ],
    [
      {
        "questionType": "textbox",
        "key": "emailAddress",
        "label": "Email",
        "value": "",
        "type": "email",
        "order": 2,
        "visibility": true
      }
    ]
  ]
  </code></pre>
  
  <p>main.componennt.html</p>
  
  <pre><code>&lt;div *ngIf="loaded"&gt;
    &lt;h2&gt;POC&lt;/h2&gt;
    &lt;form (ngSubmit)="onSubmit()" [formGroup]="form"&gt;
      &lt;ng-container *ngFor="let eachGroup of objectKeys(globalForm); let index = index"&gt;
        &lt;button (click)="openGroupHadler(index)"&gt;click me&lt;/button&gt; &lt;br&gt;
        &lt;div 
          [formGroupName]="eachGroup" 
          class="form-group"
          [ngClass]="{'active' : index === activeGroup}"&gt;
          &lt;div *ngFor="let question of globalForm[eachGroup]" class="form-row"&gt;
            &lt;app-question [question]="question" [form]="form.controls[eachGroup]"&gt;&lt;/app-question&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/ng-container&gt;
      &lt;div class="form-row"&gt;
        &lt;button type="submit" [disabled]="!form.valid"&gt;Save&lt;/button&gt;
      &lt;/div&gt;
    &lt;/form&gt;
  
    &lt;pre&gt;
      {{form.value | json}}
    &lt;/pre&gt;
    &lt;div *ngIf="payLoad" class="form-row"&gt;
      &lt;strong&gt;Saved the following values&lt;/strong&gt;&lt;br&gt;{{payLoad}}
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>main.component.ts</p>
  
  <pre><code>import { Component, OnInit } from '@angular/core';
  import { HeaderService } from '@myHeaderService';
  import { QuestionService } from '../../question/services/question.service';
  import { QuestionControlService } from '../../question/services/question-control.service';
  import { FormGroup } from '@angular/forms';
  import { FControlTextbox } from '../../question/model/question-textbox';
  import { FControlDropdown } from '../../question/model/question-dropdown';
  import { FControlCheckbox } from '../../question/model/question-checkbox';
  
  @Component({
    selector: 'app-irv',
    templateUrl: './irv.component.html',
    styleUrls: ['./irv.component.scss']
  })
  export class IrvComponent implements OnInit {
    labels;
    objectKeys = Object.keys;
    form: FormGroup;
    payLoad = '';
    loaded = false;
    globalForm: any = {};
    activeGroup;
  
    constructor(
      private _headerService: HeaderService,
      private _questionService: QuestionService,
      private _questionControlService: QuestionControlService
      ) {}
  
    ngOnInit() {
      this.labels = JSON.parse(localStorage.getItem('labels'));
  
      this._headerService.updateHeader({
        title: 'HC - Irv',
        back: true
      });
  
      this._questionService.getQuestions().subscribe((response: any[]) =&gt; {
        response.forEach((group, index) =&gt; { // loop thrugh groups
          const formControls = [];
  
          group.forEach(formControl =&gt; { // loop through form controls in groups
            switch (formControl.questionType) {
              case 'textbox':
                formControls.push(new FControlTextbox(formControl)); break;
              case 'checkbox':
                formControls.push(new FControlCheckbox(formControl)); break;
              case 'dropdown':
                formControls.push(new FControlDropdown(formControl)); break;
              default:
                break;
            }
          });
          console.log(this.globalForm);
          this.globalForm['group' + (index + 1)] = formControls.sort((a, b) =&gt; a.order - b.order);
        });
  
        this.form = this._questionControlService.toFormGroup(this.globalForm);
        this.loaded = true;
      });
    }
  
    onSubmit() {
      this.payLoad = JSON.stringify(this.form.value);
    }
  
    openGroupHadler(index) {
      this.activeGroup === index ? this.activeGroup = null : this.activeGroup = index; // show or hide a formgroup
    }
  
  }
  </code></pre>
  
  <p>question.component.ts</p>
  
  <pre><code>import { Component, Input } from '@angular/core';
  import { FormGroup } from '@angular/forms';
  
  import { QuestionBase } from './model/question-base';
  
  @Component({
    selector: 'app-question',
    templateUrl: './question.component.html',
    styleUrls: ['./question.component.scss']
  })
  export class QuestionComponent {
    @Input() question: QuestionBase&lt;any&gt;;
    @Input() form: FormGroup;
    get isValid() { return (
      (
        this.form.controls[this.question.key].valid &amp;&amp;
        this.form.controls[this.question.key].dirty
      ) ||
      (
        this.form.controls[this.question.key].untouched
      ) ||
      (
        !this.form.controls[this.question.key].invalid
      )
      );
    }
  
    isVisible(value) {
      return eval(value);
    }
  }
  </code></pre>
  
  <p>question.component.html</p>
  
  <pre><code>&lt;div [formGroup]="form" 
    [ngClass]="{'isa_error':isValid ? false : true}" 
    *ngIf="isVisible(question.visibility)"
    &gt;
      &lt;label [attr.for]="question.key"&gt;{{question.label}}&lt;/label&gt;
  
    &lt;div [ngSwitch]="question.controlType"&gt;
      &lt;input
        *ngSwitchCase="'textbox'"
        [formControlName]="question.key"
        [id]="question.key"
        [type]="question['type']"&gt;
  
      &lt;input
        *ngSwitchCase="'checkbox'"
        [formControlName]="question.key"
        [checked]="question['checked']"
        [id]="question.key"
        [type]="question['type']"&gt;
  
      &lt;select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key"&gt;
        &lt;option 
          *ngFor="let opt of question['options']" 
          [value]="opt.key"
          &gt;{{opt.value}}&lt;/option&gt;
      &lt;/select&gt;
    &lt;/div&gt; 
  
    &lt;div class="errorMessage" *ngIf="!isValid"&gt;{{question.label}} is required&lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>question.service.ts</p>
  
  <pre><code>import { Injectable } from '@angular/core';
  import { HttpClient } from '@angular/common/http';
  
  @Injectable({
    providedIn: 'root'
  })
  export class QuestionService {
    constructor(
      private _http: HttpClient
    ) {}
    getQuestions() {
      return this._http.get('./assets/meta.json').pipe(res =&gt; res);
    }
  }
  </code></pre>
  
  <p>question.control.service.ts</p>
  
  <pre><code>import { Injectable } from '@angular/core';
  import { FormControl, FormGroup, Validators } from '@angular/forms';
  
  import { QuestionBase } from '../model/question-base';
  
  @Injectable({
    providedIn: 'root'
  })
  export class QuestionControlService {
    constructor() { }
  
    toFormGroup(questions: QuestionBase&lt;any&gt;[] ) {
      let group: any = {};
      const sections: {} = {};
      Object.keys(questions).forEach((eachgroup: string) =&gt; {
        group = {};
        questions[eachgroup].forEach(question =&gt; {
          const validators = [];
          if (question.validators) {
            question.validators.forEach(element =&gt; {
              switch (element) {
                case 'required': validators.push(Validators.required); break;
                case 'email': validators.push(Validators.email); break;
              }
            });
            group[question.key] = new FormControl(question.value || '', validators);
          } else {
            group[question.key] = new FormControl(question.value || '');
          }
        });
        sections[eachgroup] = new FormGroup(group);
      });
  
      return new FormGroup(sections);
    }
  }
  </code></pre>
  
  <p>question.textbox.ts</p>
  
  <pre><code>import { QuestionBase } from './question-base';
  
  export class FControlTextbox extends QuestionBase&lt;string&gt; {
    controlType = 'textbox';
    type: string;
  
    constructor(options) {
      super(options);
      this.type = options.type || '';
    }
  }
  </code></pre>
  
  <p>question.dropdown.ts</p>
  
  <pre><code>import { QuestionBase } from './question-base';
  
  export class FControlDropdown extends QuestionBase&lt;string&gt; {
    controlType = 'dropdown';
    options: {key: string, value: string}[] = [];
  
    constructor(options) {
      super(options);
      this.options = options.options || [];
    }
  }
  </code></pre>
  
  <p>question.base.ts</p>
  
  <pre><code>export class QuestionBase&lt;T&gt; {
    value: T;
    key: string;
    label: string;
    required: boolean;
    order: number;
    controlType: string;
    visibility: string;
    validators: string;
  
    constructor(options: {
        value?: T,
        key?: string,
        label?: string,
        required?: boolean,
        order?: number,
        controlType?: string,
        visibility?: string
        validators?: string
      } = {}) {
      this.value = options.value;
      this.key = options.key || '';
      this.label = options.label || '';
      this.required = !!options.required;
      this.order = options.order === undefined ? 1 : options.order;
      this.controlType = options.controlType || '';
      this.visibility = options.visibility;
      this.validators = options.validators;
    }
  }
  </code></pre>
  
  <p>question.checkbox.ts</p>
  
  <pre><code>import { QuestionBase } from './question-base';
  
  export class FControlCheckbox extends QuestionBase&lt;string&gt; {
    controlType = 'checkbox';
    type: string;
    checked: boolean;
  
    constructor(options) {
      super(options);
      this.type = options.type || '';
      this.checked = options.checked || false;
    }
  }
  </code></pre>
  
  <p>asd</p>