Error component

Using the o-error component allows to define multiple errors messages associated to its parent o-validator component.

Example

<o-text-input attr="input" label="{{ 'INPUT.BUTTON.TEXT' | oTranslate }}">
  <o-validator [validator-function]="aValidator">
    <o-error name="requiredLowercaseA" text="Must contain a lowercase 'a'"></o-error>
    <o-error name="requiredUppercaseA" text="Must contain a uppercase 'A'"></o-error>
  </o-validator>
</o-text-input>
  ...

  import { ValidationErrors, FormControl } from '@angular/forms';

  aValidator(control: FormControl): ValidationErrors {
    let result = {};
    if (control.value && control.value.toString().indexOf('a') === -1) {
      result['requiredLowercaseA'] = true;
    }
    if (control.value && control.value.toString().indexOf('A') === -1) {
      result['requiredUppercaseA'] = true;
    }
    return result;
  }

  ...
<o-text-input attr="input" label="{{ 'INPUT.BUTTON.TEXT' | oTranslate }}">
  <o-validator [async-validator-function]="asyncLowercaseAValidator">
    <o-error name="requiredLowercaseA" text="Must contain a lowercase 'a'"></o-error>
  </o-validator>
</o-text-input>
...
asyncLowercaseAValidator: AsyncValidatorFn;

constructor(private charValidatorService: CharValidatorService) {
  this.asyncLowercaseAValidator = AsyncValidatorsHelper.createValidator(this.charValidatorService.containsLowercaseA())
}
...
interface CharValidator {
  fn: (value: string) => Observable<boolean>
  error: { [key: string]: boolean; }
}


@Injectable({
  providedIn: 'root',
})
export class CharValidatorService {

  containsLowercaseA(): CharValidator {
    return {
      fn: (value: string): Observable<boolean> => {
        return of(value.indexOf('a') !== -1).pipe(delay(1000))
      },
      error: {
        'requiredLowercaseA': true
      }
    }
  }

  containsUppercaseA(): CharValidator {
    return {
      fn: (value: string): Observable<boolean> => {
        return of(value.indexOf('A') !== -1).pipe(delay(1000))
      },
      error: {
        'requiredUppercaseA': true
      }
    }
  }

  containsB(): CharValidator {
    return {
      fn: (value: string): Observable<boolean> => {
        return of(value.indexOf('b') !== -1).pipe(delay(1000))
      },
      error: {
        'requiredB': true
      }
    }
  }
}
export class AsyncValidatorsHelper {
  static createValidator(validator: CharValidator): AsyncValidatorFn {
    return (control: AbstractControl): Observable<ValidationErrors> => {
      return control.value ?
        validator.fn(control.value)
          .pipe(
            map((isValid: boolean) => isValid ? null : validator.error)
          )
        : of(null)
    };
  }
}