UniqueValidator

Overview

The UniqueValidator is a custom Angular Forms validator designed to check for uniqueness across multiple fields within a FormArray or FormGroup. It ensures that each control's value is unique among all other controls within the array or group.

Usage

Usage Scenario 1: Array of FormControls

If you have an array of individual FormControls and want to ensure uniqueness, follow these steps:

  1. Attach UniqueValidator.unique() to the FormArray you want to validate.
  2. Trigger the control's updateValueAndValidity() method as needed.
Control value should be unique
Control value should be unique
@Component({
  template: `
    <form clrForm [formGroup]="form1">
      <ng-container formArrayName="demo1">
        <clr-input-container *ngFor="let control of form1.controls.demo1.controls; let i = index">
          <label [attr.for]="i">Control {{ i + 1 }}</label>
          <input clrInput type="text" [formControlName]="i" (blur)="validateControlByIndex(i)" />
          <clr-control-helper>Control value should be unique</clr-control-helper>
          <clr-control-error *clrIfError="'notUnique'">Duplicated</clr-control-error>
        </clr-input-container>
      </ng-container>
    </form>
`
})
export class DemoComponent {
  private fb = inject(FormBuilder);

  form1 = this.fb.group({
    demo1: this.fb.array([this.fb.control(''), this.fb.control('')], UniqueValidator.unique()),
  });

  validateControlByIndex(index: number) {
    this.form1.controls.demo1.controls[index].updateValueAndValidity();
  }
}

Usage Scenario 2: Array of FormGroups with Key-Value Pairs

In a more complex scenario, imagine you have an array of FormGroups, each containing key-value pairs as FormControls. You want to ensure the uniqueness of the key controls' values (left controls below) across all groups. For this case, you can pass a control selector as the argument of UniqueValidator.unique(controlSelector). The selector depends on how you build the form. Please check the below code about how to obtain key controls and validate against themselves.

key control should be unique
value control has not validation
key control should be unique
value control has not validation
@Component({
  template: `
    <form clrForm [formGroup]="form2">
      <ng-container formArrayName="demo2">
        <div
          *ngFor="let group of form2.controls.demo2.controls; let i = index"
          [formGroup]="group"
          style="display: flex; gap: 1rem"
        >
          <clr-input-container>
            <label class="clr-sr-only">key</label>
            <input
              clrInput
              [formControl]="group.controls.key"
              (blur)="validateControl(group.controls.key)"
              [size]="30"
            />
            <clr-control-helper>key control should be unique</clr-control-helper>
            <clr-control-error *clrIfError="'notUnique'">Duplicated</clr-control-error>
          </clr-input-container>
          <clr-input-container>
            <label class="clr-sr-only">value</label>
            <input clrInput [formControl]="group.controls.value" [size]="30" />
            <clr-control-helper>value control has not validation</clr-control-helper>
          </clr-input-container>
        </div>
      </ng-container>
    </form>
`
})
export class DemoComponent {
  private fb = inject(FormBuilder);

  form2 = this.fb.group({
    demo2: this.fb.array(
      [this.fb.group({key: '', value: ''}), this.fb.group({key: '', value: ''})],
      UniqueValidator.unique((control) => (control as FormGroup<{key: FormControl<string>}>).controls.key),
    ),
  });

  validateControl(control: AbstractControl) {
    control.updateValueAndValidity();
  }
}