Получить валидаторы, присутствующие в FormGroup/FormControl

Я использую Material 2 в своем приложении, но в этом вопросе я хочу решить проблему специально с Ввод.

Как вы можете видеть в Справочнике API, существует привязка свойства required, которая отображается как звездочка в заполнителе.

Итак, мне интересно, есть ли способ проверить, имеет ли элемент управления формы специальный валидатор в Angular, потому что я действительно не хочу устанавливать вручную для каждого входа [required]="true/false"

Я прочитал AbstractControl документы, и я ничего не нашел об этом. Я столкнулся с методом hasError (который по иронии судьбы не документирован в нигде... ни в FormGroup, ни в FormControl, ни в AbstractControl), однако это не что я ищу. Он просто проверяет, имеет ли элемент управления формы ошибку, но, как вы, возможно, читали, я хочу проверить, есть ли у элемента управления определенные специальные валидаторы...

Некоторые коды:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="anyCtrl.hasValidator('required')"> <!-- something like this -->
</md-input-container>

Надеюсь, этот вопрос достаточно ясен. Спасибо заранее.

Ответ 1

Angular действительно не обеспечивает отличный, чистый способ сделать это, но это возможно. Я думаю, что валидаторы хранятся в службе, которая вводится в FormBuilder (NG_VALIDATORS), и я собираюсь изучить захват этой услуги или ее встраивание в компонент, но пока это будет работать:

docs, а источник показывает член validator на AbstractControl, набранный в ValidatorFn. ValidatorFn, к сожалению, просто имеет ввод null, поэтому мы не можем видеть, что происходит. Однако, просунув через сгенерированный источник и исследуя приложение, кажется, мы можем передать этот validators метод a control параметр, который вернет объект всех валидаторов, присутствующих в этом элементе управления, независимо от того, проходит он или нет.

Странно, этот только работает только с FormControl, а не с FormGroupFormGroup, член validators не является функцией и всегда был null в мое тестирование). Скомпилированный JS говорит, что эта функция принимает параметр control; Я пробовал передавать ссылки FormControl, но, насколько я могу судить, он просто вернет валидаторы в элементе управления, пока этот параметр не равен нулю.

Получение валидаторов на FormControl

// in the constructor
this.myForm = this.formBuilder.group({
  'anyCtrl': ['', Validators.required],
  'anotherCtrl': ['', Validators.compose([Validators.required, Validators.email])]
});

// later on 
let theValidators = this.myForm.controls['anyCtrl'].validator('');
console.log(theValidators) // -> {required: true};

let otherValidators = this.myForm.controls['anotherCtrl'].validator('');
console.log(otherValidators); // -> {required: true, email: true}

Упрощение захвата:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}

и в вашей разметке:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="hasValidator('anyCtrl', 'email')">
</md-input-container>

Специальный случай для Validators.required

Валидатор required имеет ярлык. Связывание [required] на самом деле является экземпляром директивы RequiredValidator (строка 5022 источника /forms.js). Эта директива фактически добавит валидатор required к FormControl. Это эквивалентно добавлению Validators.required к FormGroup при инициализации. Таким образом, установка связанного свойства в false приведет к удалению required Validator из этого элемента управления и наоборот... в любом случае директива воздействует на значение FormControl.required, поэтому привязка его к свойству, которое он изменяет, действительно не будет много.

Единственное отличие состоит в том, что директива [required] добавляет звездочку к заполнителю, а Validators.required - нет.

Я буду продолжать смотреть NG_VALIDATORS, но надеюсь, что это поможет сейчас!

Ответ 2

Этот ответ является продолжением @joh04667. Они написали:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}

Однако нет метода AbstractControls.validators(). Я предполагаю, что AbstractControls.validator() имел в виду.

Метод hasValidator() работает только для валидаторов, которые "терпят неудачу" (например, требуемый валидатор для элемента управления со значением "" (пусто)). Поскольку, если они проходят, они возвращают ноль. Обойти это можно было бы, установив значение так, чтобы оно всегда завершалось ошибкой, и восстанавливая его впоследствии.

public hasValidator(control: string, validator: string): boolean {
    let control: AbstractControl = this.myForm.controls[control];
    let lastValue: any = control.value;
    switch(validator) {
        case 'required':
            control.setValue('');  // as is appropriate for the control
        case 'pattern':
            control.setValue('3'); // given you have knowledge of what the pattern is - say its '\d\d\d'
        ....
    }
    let hasValidator: boolean = !!control.validator(control).hasOwnProperty(validator);

    control.setValue(lastValue);
    return hasValidator;
}

И это довольно ужасно. Напрашивается вопрос - Почему нет AbstractControl.getValidators(): ValidatorFn[]|null?

Какова мотивация скрывать это? Возможно, они обеспокоены тем, что кто-то может вставить их код:

...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...

Ответ 3

Я настроил код из joh04667 и HankCa так:

export const hasValidator = (form: FormGroup, controlPath: string, validator: string): boolean => {
  const control = form.get(controlPath);
  const validators = control.validator(control);
  return !!(validators && validators.hasOwnProperty(validator));
};

Который я храню в файле с именем util.ts и импортирую в компонент, который содержит такую форму:

import * as util from '@app/shared/util';

И определите util в своем классе:

public util = util;

Добавьте директиву к вашему компоненту ввода следующим образом:

[required]="util.hasValidator(myForm, 'path.to.control', 'required')"