1

My template:

          <input mdInput
                 [mdAutocomplete]="auto"
                 [(ngModel)]="formData.areaName"
                 (keyup)="updateFilteredAreas(formData.areaName)"
                 class="form-control {{areaName.errors && (areaName.dirty || areaName.touched) ? 'failed-validation' : ''}}"
                 name="areaName"
                 #areaName="ngModel"
                 arrayIncludes="one,two,three"
                 required>

          <div *ngIf="areaName.errors && (areaName.dirty || areaName.touched)"
               [hidden]="!areaName.errors.arrayIncludes"
               class="validation-error">
            Please enter a value from the array
          </div>

My custom validator:

export class CustomValidators {

  public static arrayIncludes(arrayIncludes: string): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } => {
      if (isPresent(Validators.required(control))) {
        return null;
      }

      let arrayFromString = arrayIncludes.split(",");

      let value: string = control.value;

      return arrayFromString.includes(value) ?
        null :
        { arrayIncludes: { valid: false } };
    };
  }
}

Helper function:

function isPresent(obj) {
    return obj !== undefined && obj !== null;
}

Validation directive:

const ARRAY_INCLUDES_VALIDATOR = {
    provide: NG_VALIDATORS,
    useExisting: forwardRef(() => ArrayIncludesValidator),
    multi: true
};

@Directive({
  selector: '[arrayIncludes][ngControl],[arrayIncludes][ngFormControl],[arrayIncludes][ngModel]',
  providers: [ARRAY_INCLUDES_VALIDATOR]
})
export class ArrayIncludesValidator implements Validator {
  private _validator: any;

  constructor(@Attribute('arrayIncludes') arrayIncludes: string) {
    this._validator = CustomValidators.arrayIncludes(arrayIncludes);
  }

  public validate(control: AbstractControl): {[key: string]: any} { return this._validator(control); }
}

So far I can put a string as a value to the directive in template:

arrayIncludes="one,two,three"

and then convert the string to an array, with the result being that only "one", "two", "three" values are allowed. What I need is to pass an object from the controller to the directive, which is an array of objects. Those objects have propery "area.name", and each "area.name" is a valid input. When i use the syntax:

[arrayIncludes]="filteredAreas"

with "filteredAreas" being my object, the error I get is

Error: Template parse errors:
Can't bind to 'arrayIncludes' since it isn't a known property of 'input'. ("
                 name="areaName"
                 #areaName="ngModel"
                 [ERROR ->][arrayIncludes]="filteredAreas"
                 required>

"): ng:///RegistrationModule/ConsumerFormComponent.html@42:21

How do I refactor my custom validator to accept the object via a template. It must have something to do with the "@Input" decorator. My issue is very similar to this thread, however, it seems to lack the information I need.

1 Answer 1

4

If you want to pass an object you should use @Input instead of @Attribute

@Directive({...})
export class ArrayIncludesValidator implements Validator {
  private _validator: any;

  @Input() arrayIncludes: any;

  ngOnInit() {
    this._validator = CustomValidators.arrayIncludes(this.arrayIncludes);
  }

  public validate(control: AbstractControl): {[key: string]: any} { return this._validator(control); }
}
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.