0

I have an Angular 2 Reactive form using FormGroup. I need to compare the values of two fields, so I am passing a validator to the FormGroup upon creation. The validation works great:

this.form = this.formBuilder.group({
  add: this.formBuilder.group({
    mobile: ['', [
      Validators.required,
      this.duplicate
    ]],
    voice: [false]
  }),
  existing: this.formBuilder.array([])
}, {validator: this.validateDuplicates});

validateDuplicates(group: FormGroup): any {
  let adding = group.get('add').get('mobile').value;
  if (!adding) {
    return null;
  }

  let matches: boolean[] = (group.get('existing') as FormArray).controls
    .map(control => {
      return control.get('number').value;
    })
    .filter(val => val === adding);

  return matches.length > 0 ? {
    duplicate: {adding}
  } : null;
}

After I enter an invalid value, the form.errors.duplicate field is populated correctly, and the form group is marked with an ng-invalid CSS class in the DOM.

The only gap I have is that I would like a specific form control to be marked as ng-invalid when this group-level validator fails. Is there any way to do that? I have tried messing with the object returned from the validator function to match the nested layer of the target form control, to no avail.

In the short term I have been able to work around it by adding additional markup and styling on a specific element when the form is invalid, but ideally I would like to be able to get rid of that, and address specific error codes in the markup for that control only, rather than going up to the parent form group level:

<md-input-container class="primary" floatPlaceholder="never">
    <input mdInput name="mobile" type="text" pattern="^\([0-9]{3}\)\s[0-9]{3}\-[0-9]{4}$" placeholder="Number" formControlName="mobile" required>
    <md-hint *ngIf="!addControl.touched &amp;&amp; addControl.invalid" align="start" color="warn">(202) 555-5555</md-hint>
    <md-hint *ngIf="addControl.touched &amp;&amp; addControl.invalid" align="end" color="warn">Format must be (###) ###-####</md-hint>
    <!-- Workaround I'd like to remove -->
    <md-hint *ngIf="form.errors &amp;&amp; form.errors.duplicate">Numbers must be unique</md-hint>
</md-input-container>
1
  • At first, when you use reactive forms the recommended way (and maybe the right one) to add validators is in component, not in template.. so in your case, Pattern and required must go only in component. Also, there-s md-error in Material2 that you can use to show errors. Now about your problem, a plunker to demonstrate it would be good. Commented May 9, 2017 at 16:37

1 Answer 1

2

To mark a specific control as invalid and assign it an arbitrary error of your choice, you could use the setErrrors method on the control of your choice. This also sets the validity of the parent control/group.

For example after pinning down the faulty control[s] containing [a] duplicate value[s], you could do this in your custom validator method:

faultyCtrl.setErrors({duplicate: true});

Don't forget to also return the error from your custom validator to properly set the errors property on the group, because setErrors only sets the status property, but not the errors (see this for further info)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.