23
votes

Is there a way to update the Validtors of a FormControl Object? I have FormGroup where one Input is a select field, when the value of the select field changes I want the other FormControl in my FormGroup to change the validator.

Here is my subscribeToFormChanges() method from my FormGroup component:

private appIdRegexes = {
    ios: /^[a-zA-Z][a-zA-Z0-9]*(\.[a-zA-Z0-9\-]+){2,}$/,
    android: /^([a-zA-Z])[a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9\-]*){2,}$/,
    any: /^any$/
  };

private subscribeToFormChanges(): void {
    const myFormValueChanges$ = this.appsForm.valueChanges;
    myFormValueChanges$.subscribe(x => {
      const platform = this.appsForm.controls['platform'].value;
      const appId = this.appsForm.controls['appId'].value;

      if (this.appIdRegexes[platform]) {
        this.appsForm.controls['appId'] = new FormControl(appId, Validators.pattern(this.appIdRegexes[platform].source));
      }
    });
  }

And here's the html template:

<div class="row" [formGroup]="appsForm">
  <div class="form-group col-xs-6">
    <label>Platform</label>

    <select id="licensePlatform" class="form-control"
            formControlName="platform">
      <option *ngFor="let platform of licensePlatforms" [value]="platform">
        {{platform}}
      </option>
    </select>

    <small [hidden]="appsForm.controls.platform.valid">
      Platform is required
    </small>
  </div>

  <div class="form-goup col-xs-6">
    <label>App ID</label>
    <input type="text" class="form-control" formControlName="appId">
    <small [hidden]="appsForm.controls.appId.valid">
      Please use the right ID format
    </small>
  </div>
</div>

When I'm implementing the subscribeToFormChanges() method like shown here, appsForm.controls.appId.value doesn't update anymore when writing into the input field. Initially the value is updating.

3
Use patch value to update form this.form.patchValue({controlTobeUpdated:value}); angular.io/docs/ts/latest/api/forms/index/… - manish.nith
@user32 but patchValue() allows me to only update the value - not the Validator? - Markus Török
Right. patchValue() allows you to update value, but once that value will be update validators will be fired. - manish.nith
now i understand ur problem, i was suggesting something else. - manish.nith

3 Answers

16
votes

I solved the issue by listening to valueChanges on my platform select field and then I use the setValidators() method on the appId input field. This article was quite helpful.

Here's my solution:

 private subscribePlatformChanges() {
    const platformCtrl = this.appsForm.controls['platform'];
    const changes$ = platformCtrl.valueChanges;

    changes$.subscribe(platform => {
      this.appsForm.controls['appId'].setValidators([Validators.pattern(this.appIdRegexes[platform].source),
                                                    Validators.required]);
      this.appsForm.controls['appId'].updateValueAndValidity();
    });
  }
4
votes

To recheck the controls within a FormGroup, you can do something with the updateValueAndValidity of the FormControl.

If this.appsForm is indeed a FormGroup:

this.appsForm.controls.forEach(control => control.updateValueAndValidity());
0
votes

you can fire a change event from the select as below

<select id="licensePlatform" class="form-control"
            formControlName="platform"  (change)="update($event.target.value)" >
      <option selected="selected" disabled="disabled" value="">Select Card Type</option>
      <option *ngFor="let platform of licensePlatforms" [value]="platform" >
        {{platform}}
      </option>
    </select>

And in the component you can write the update function as below

update(value){
      if(value){
        (<FormControl>this.appsForm.controls['platform']).setValue(value, {onlySelf: false});
        const appId = this.appsForm.controls['appId'].value;
        if (this.appIdRegexes[value]) {
        this.appsForm.controls['appId'] = new FormControl(appId, Validators.pattern(this.appIdRegexes[value].source));
      }
    };

  }

This will update the validator according to the choice you make in the dropdown. I believe this will resolve your issue.