vdubus
vdubus

Reputation: 456

How to manage a checkbox inside an Augular dynamic form?

I have some problem making a checkbox works in a dynamic form using Angular 4.

On firefox, when checking the checkbox, the value I get is 'on' in place of true. And when unchecking it, the value is still there and not set to false or ''.

On chrome, it doesn't even seem to work...

I have created an example bases on the Angular dynamic form tutorial.

I have added a new file named question-checkbox.ts to manage a checkbox:

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

export class CheckboxQuestion extends QuestionBase<boolean> {
  controlType = 'checkbox';
  type: string;

  constructor(options: {} = {}) {
    super(options);
    this.type = 'checkbox';
  }
}

Then, I have updated the dynamic-form-question.component.html to use this new type:

<div [formGroup]="form">
  <label [attr.for]="question.key">{{question.label}}</label>
  <div [ngSwitch]="question.controlType">
    <select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key">
      <option *ngFor="let opt of question.options" [value]="opt.key">{{opt.value}}</option>
    </select>
    <input *ngSwitchDefault [formControlName]="question.key" [id]="question.key" [type]="question.type" />
  </div>
  <div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div>

And, I have updated the dataset in question.service.ts:

import { Injectable }       from '@angular/core';
import { DropdownQuestion } from './question-dropdown';
import { QuestionBase }     from './question-base';
import { TextboxQuestion }  from './question-textbox';
import { CheckboxQuestion }  from './question-checkbox';

@Injectable()
export class QuestionService {

  getQuestions() {

    let questions: QuestionBase<any>[] = [

      new DropdownQuestion({
        key: 'brave',
        label: 'Bravery Rating',
        options: [
          { key: 'solid', value: 'Solid' },
          { key: 'great', value: 'Great' },
          { key: 'good', value: 'Good' },
          { key: 'unproven', value: 'Unproven' }
        ],
        order: 3
      }),

      new TextboxQuestion({
        key: 'firstName',
        label: 'First name',
        value: 'Bombasto',
        required: true,
        order: 1
      }),

      new TextboxQuestion({
        key: 'emailAddress',
        label: 'Email',
        type: 'email',
        order: 2
      }),

      new CheckboxQuestion({
        key: 'sideksick',
        label: 'Sidekick',
        order: 3
      })
    ];

    return questions.sort((a, b) => a.order - b.order);
  }
}

Lastly, I have updated the dynamic-form.component.html to display the current state of the form:

<div>
  <form [formGroup]="form">
    <div *ngFor="let question of questions" class="form-row">
      <df-question [question]="question" [form]="form"></df-question>
    </div>
  </form>
  <p><strong>Current state</strong><br>{{form.value | json}}</p>
</div>

Example available on Plunker

So my question would be: How should I do to be able to use checkboxes inside an Angular 4 dynamic form, and be able to get a correct value?

As for why I need to use a dynamic form, it is because I am generating my form based on a JSON coming from an outside service which describe it.

Upvotes: 0

Views: 758

Answers (1)

vdubus
vdubus

Reputation: 456

New answer

It seems there is a really strange behavior which cause this problem with Angular 4.x.

Writing this won't work:

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

But writing this does work:

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

The only difference is that we don't use Angular template functionalities ([type]="question.type", [attr.type]="question.type" or type={{question.type}}) to write the content of type, and so we only use the native type from HTML.
This seems like a bug to me...

Here the fix on Plunker.


Old answer

The solution above is the only one you should consider.

I found an hint from the answer of angular2-dynamic-form-checkbox.

I was missing the following part in the file dynamic-form-question.component.html: [(ngModel)]="question.value" (change)="question.value = ckb.checked" #ckb.

<select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key">
  <option *ngFor="let opt of question.options" [value]="opt.key">{{opt.value}}</option>
</select>
<input *ngSwitchCase="'checkbox'" [formControlName]="question.key" [id]="question.key" [type]="question.type" [(ngModel)]="question.value" (change)="question.value = ckb.checked" #ckb />
<input *ngSwitchDefault [formControlName]="question.key" [id]="question.key" [type]="question.type" />

It seems that in the case of a dynamic form, checkboxes aren't manage automatically, and so we need to update their value on change in function of the checked state of the checkbox.

Here the fix on Plunker.

Upvotes: 0

Related Questions