Varun Varun - 7 months ago 301
TypeScript Question

Angular 2 Dynamic Form - Implement Clear Functionality

I'm trying to implement Clear functionality for Angualr 2 dynamic forms, which should clear all the values to null. But i'm getting an error when i try to use

to replace each value in the form.

Working Code:

Typescript class code:

import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, REACTIVE_FORM_DIRECTIVES } from '@angular/forms';
import { QuestionBase } from './question-base';
import { QuestionControlService } from './question-control.service';

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

@Input() questions: QuestionBase<any>[] = [];
form: FormGroup;
questiont: QuestionBase<any>;
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
console.log("Form Init",this.questions);
this.questiont = JSON.parse(JSON.stringify(this.questions));
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
this.questiont = JSON.parse(JSON.stringify(this.questions));
this.questions = JSON.parse(JSON.stringify(this.questiont));
for(var i=0;i<this.questions.length;i++){

HTML code:

<form [formGroup]="form">

<div *ngFor="let question of questions" class="form-row">
<label [attr.for]="question.key">{{question.label}}</label>

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

<input *ngSwitchCase="'textbox'" [formControlName]="question.key"
[id]="question.key" [type]="question.type" [(ngModel)]="question.value">

<select [id]="question.key" [(ngModel)]="question.value" *ngSwitchCase="'dropdown'" [formControlName]="question.key" >
<option *ngFor="let opt of question.options" [ngValue]="opt.key" >{{opt.value}}</option>

<div class="errorMessage" *ngIf="!form.controls[question.key].valid">{{question.label}} is required</div>

<div class="form-row">
<button type="submit" [disabled]="!form.valid" (click)="onSubmit()">Save</button>
<button type="button" class="btn btn-default" (click)="cancel()">Cancel</button>
<button type="button" class="btn btn-default" (click)="clear()">Clear</button>


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

Is there any way that can be done without getting error.


The problem is with your logic to check and display a message if a field is required. Your plunker code was throwing the exception Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'

The problem is that it runs over your template code with values for questions[i].value but then it changes once you call clear. Angular compares questions[i].value and notices it's different then when it started rendering and thinks it made a mistake. It didn't pick up that you changed the value yet. You have to let it know the value was changed.

If you were to run the code with prod enabled, it wouldn't run this safety check and you'd get no error, but don't enable prod mode just to fix this.


The fix is import ChangeDetectorRef from @angular/core to dynamic.form.component.ts

Add private cdr: ChangeDetectorRef to the constructor

and add this.cdr.detectChanges(); to the end of your clear() method.

This will let know angular pick up that changes have happened and it won't think it made a mistake

P.S. the lines that are culprits are

<div class="errorMessage" *ngIf=" form && !form.controls[question.key].valid">{{question.label}} is required</div>


group[question.key] = question.required ? new FormControl(question.value || '', Validators.required) : new FormControl(question.value || ''); });