Ka Mok
Ka Mok

Reputation: 1988

How do you use multiple arguments in Custom Validation Directives in Angular 5?

For example, the Angular documentation here uses the following directive for the forbiddenName validation:

@Directive({
  selector: '[appForbiddenName]',
  providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
})
export class ForbiddenValidatorDirective implements Validator {
  @Input('appForbiddenName') forbiddenName: string;

  validate(control: AbstractControl): {[key: string]: any} {
    return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
                              : null;
  }
}

Is it possible to use a @Input of say Object or string[] instead of only allowing strings? If not, how do you pass in multiple arguments?

The Angular docs uses it in the example as such:

<input id="name" name="name" class="form-control"
       required minlength="4" appForbiddenName="bob"
       [(ngModel)]="hero.name" #name="ngModel" >

Upvotes: 3

Views: 3982

Answers (1)

DeborahK
DeborahK

Reputation: 60596

Multiple strings with a separator

You can pass multiple strings with a separator.

For example, I defined a range validator as follows:

                    <input class="form-control" 
                            id="inputStarRating" 
                            type="text" 
                            placeholder="Rating"
                            mhRange="1,5"
                            [(ngModel)] = "movie.starRating"
                            name="starRating"
                            #starRatingVar = "ngModel" />

The directive then had code as follows:

  constructor(@Attribute('mhRange') range: string) {
    const arr = range.split(',');
    let min = 1;
    let max = 10;
    if (arr[0]) { min = parseInt(arr[0], 10); }
    if (arr[1]) { max = parseInt(arr[1], 10); }
    this.validator = NumberValidators.range(min, max);
  }

Notice that this uses a split to pull apart the two different values.

Arrays

You can also pass arrays like this:

  @Input('appForbiddenName') forbiddenName: string[];

  validate(control: AbstractControl): {[key: string]: any} {
    console.log(this.forbiddenName);
    return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName[0], 'i'))(control)
                              : null;
  }

NOTE: To minimize changes in the above code, I just checked the first element. But you could change it to loop through the array.

The HTML then looks like this:

    <input id="name" name="name" class="form-control"
           required minlength="4" [appForbiddenName]="powers"
           [(ngModel)]="hero.name" #name="ngModel" >

Notice how it uses binding to bind to the array of values.

Objects

You can define objects like this:

  @Input('appForbiddenName') forbiddenName: Hero;

  validate(control: AbstractControl): {[key: string]: any} {
    console.log(this.forbiddenName);
    return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName.alterEgo, 'i'))(control)
                              : null;
  }

Assuming there is a type Hero defined. For the sample app from the documentation, I had to use any because no Hero type was defined.

The HTML then looks like this:

    <input id="name" name="name" class="form-control"
           required minlength="4" [appForbiddenName]="hero"
           [(ngModel)]="hero.name" #name="ngModel" >

Bottom line, you cannot pass anything but a string to the attribute, but that string can be a binding.

So doing something like this:

appForbiddenName='{"name":"Dr.", "alterEgo":"Dr. What", "power":"test"}'

Just provides it as a string. You'd have to write the code to parse it and turn it back into an object:

  @Input('appForbiddenName') forbiddenName: string;

  validate(control: AbstractControl): {[key: string]: any} {
    const hero: Hero = JSON.parse(this.forbiddenName);
    console.log(hero.alterEgo);
    return this.forbiddenName ? forbiddenNameValidator(new RegExp(hero.alterEgo, 'i'))(control)
                              : null;
  }

Upvotes: 4

Related Questions