2

i'm using angular Reactive Forms with Form Validations. I would like to create a select input, and only if a specific option is selected ('Other') I want to show additional text input (so user can enter custom answer). I made the text input not required by default, then onValueChanged i'm checking if option is 'Other' and use setValidators to change the input to required.This seem to work, but i'm getting this error:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.

Here is my code:

component.ts

 buildForm() {
    this.validationForm = this.formBuilder.group({
      PaymentMethod: this.formBuilder.control(null, [Validators.required]),
      Package: this.formBuilder.control(null, [Validators.required]),
      CustomAmount: this.formBuilder.control(null, [Validators.min(50), Validators.max(400)]),
    });

    this.validationForm.valueChanges
      .subscribe((data) => this.onValueChanged(data));

    this.onValueChanged(); // (re)set validation messages now
  }

  onValueChanged(data?: any) {
    if (data && data.Package && data.Package.Name === 'Other') {
      console.log('amount should be required now');
      this.validationForm.controls.CustomAmount.setValidators([Validators.min(50), Validators.max(400), Validators.required]);

    }else {
      this.validationForm.controls.CustomAmount.setValidators([Validators.min(50), Validators.max(400)]);
    }
  ...
  }

component.html

 <form [formGroup]="validationForm" (ngSubmit)="onSubmit()" novalidate>
    <div class="form-group">
      <p>
        <strong style="display: inline-block; width: 120px;">Payment Method</strong>
        <md-radio-group class="md-radio-group-spacing" formControlName="PaymentMethod" [(ngModel)]="radio.group1">
          <md-radio-button value="Cash">Cash</md-radio-button>
          <md-radio-button value="Credit">Credit</md-radio-button>
        </md-radio-group>
      </p>
      <p>
        <md-select *ngIf="packages" placeholder="Choose Package" formControlName="Package" [(ngModel)]="selectedPackage">
          <md-option *ngFor="let package of packages" [value]="package">
            {{ package.Name }} <span class="blue-500"> {{ package.Price | currency:'USD':true  }}</span>
          </md-option>
        </md-select>
      </p>
      <div *ngIf="selectedPackage" class="callout callout-info">
        <strong>Selected:</strong> {{selectedPackage.Name}}
        <p>{{selectedPackage.Description}}</p>
      </div>
      <div *ngIf="selectedPackage && selectedPackage.Name == 'Other'">
        <div class="form-group">
          <md-input-container class="full-width">
            <input type="number" mdInput formControlName="CustomAmount" placeholder="Enter Amount">
          </md-input-container>
          <small *ngIf="formErrors.CustomAmount" class="red-500">
            {{ formErrors.CustomAmount }}
          </small>
        </div>
      </div>
    </div>

  <button md-raised-button type="submit" class="btn-w-md" color="primary" [disabled]="!validationForm.valid">Submit</button>
  <span class="space space-md"></span>
  <button md-raised-button type="button" class="btn-w-md" (click)="dialogRef.close('Cancel')">Cancel</button>
  </form>

edit I found a solution here that is to enable/disable the input. works great! but i'm still happy to hear thoughts and other solutions you think are best. thanks

Shaniqwa
  • 1,924
  • 2
  • 17
  • 29
  • Possible duplicate of [Expression \_\_\_ has changed after it was checked](https://stackoverflow.com/questions/34364880/expression-has-changed-after-it-was-checked) – AT82 Jul 18 '17 at 13:26
  • 1
    Use `ChangeDetectorRef`, also I strongly suggest you use the form controls instead of `[(ngModel)]`, using `ngModel` is discouraged with reactive forms, and as I have also noticed it can cause problems. So utilize the form controls instead, when you are already using them, `ngModel` is redundant :) – AT82 Jul 18 '17 at 13:27
  • Thanks @AJT_82 , I didn't realize that it's bad practice to use `ngModel` like that. I will look into `ChangeDetectorRef` – Shaniqwa Jul 19 '17 at 07:37
  • Yes, `ngModel` directive is not even included in the `ReactiveFormsModule`, so it's clearly not intended to use with reactive forms. So like I said, you can use the form controls, and at the same time get rid of extra variables :) So instead of `selectedPackage.theProperty` you can do... `pathToFormControlHere.value.theProperty` And yes, `changeDetectorRef` will solve your problem (tried it) :) – AT82 Jul 19 '17 at 08:58

0 Answers0