Как получить имя поля ввода из объекта Angular2 FormControl?

У меня есть приложение Angular 2, которое использует модуль ReactiveForms для управления формой, использующей специальный валидатор. Валидатор получает объект FormControl. У меня есть несколько полей ввода, которые могут использовать один и тот же настраиваемый валидатор, если только я знал имя поля, когда FormControl был передан валидатору.

Я не могу найти какой-либо метод или публичное свойство в FormControl которое предоставляет имя поля ввода. Это достаточно просто, чтобы увидеть его ценность, конечно. Ниже показано, как я хотел бы использовать его:

public asyncValidator(control: FormControl): {[key: string]: any} {
  var theFieldName = control.someMethodOfGettingTheName(); // this is the missing piece

  return new Promise(resolve => {
      this.myService.getValidation(theFieldName, control.value)
        .subscribe(
          data => {
            console.log('Validation success:', data);
            resolve(null);
          },
          err => {
            console.log('Validation failure:', err);
            resolve(err._body);
          });
    });
  }

Ответ 1

Мы можем использовать свойство .parent, ну сегодня ["_parent"] (см. Ниже):

export const getControlName = (control: ng.forms.AbstractControl) =>
{
    var controlName = null;
    var parent = control["_parent"];

    // only such parent, which is FormGroup, has a dictionary 
    // with control-names as a key and a form-control as a value
    if (parent instanceof ng.forms.FormGroup)
    {
        // now we will iterate those keys (i.e. names of controls)
        Object.keys(parent.controls).forEach((name) =>
        {
            // and compare the passed control and 
            // a child control of a parent - with provided name (we iterate them all)
            if (control === parent.controls[name])
            {
                // both are same: control passed to Validator
                //  and this child - are the same references
                controlName = name;
            }
        });
    }
    // we either found a name or simply return null
    return controlName;
}

и теперь мы готовы скорректировать наше определение валидатора

public asyncValidator(control: FormControl): {[key: string]: any} {
  //var theFieldName = control.someMethodOfGettingTheName(); // this is the missing piece
  var theFieldName = getControlName(control); 
  ...

.parent позже, ["_parent"] Теперь

На данный момент (сегодня, сейчас) текущий выпуск:

2.1.2 (2016-10-27)

Но следуя этой проблеме: feat (forms): make 'parent' публичное свойство 'AbstractControl'

И как уже сказано здесь

2.2.0-beta.0 (2016-10-20)

Характеристики

  • forms: make 'parent' public property 'AbstractControl' (# 11855) (445e592)
  • ...

мы могли бы позже изменить ["_parent"] на .parent

Ответ 2

Чтобы расширить ответ Радима Кёлера. вот более короткий способ написания этой функции.

getControlName(c: AbstractControl): string | null {
    const formGroup = c.parent.controls;
    return Object.keys(formGroup).find(name => c === formGroup[name]) || null;
}

Ответ 3

У вас есть два варианта:

С помощью декоратора Attribute:

constructor(@Attribute('formControlName') public formControlName) {}

С помощью декоратора Input:

@Input() formControlName;

Чтобы использовать это, ваша проверка должна быть директивой, конечно.

Ответ 4

Начиная с FormControl Angular 4.2.x вы можете получить доступ к родительской FormGroup FormControl FormGroup (и ее элементам управления), используя общедоступное родительское свойство:

private formControl: FormControl;

//...

Object.keys(this.formControl.parent.controls).forEach((key: string) => {
  // ...
});

Ответ 5

Вы можете установить имя элемента управления в валидаторах:

    this.form = this.fb.group({
        controlName:      ['', [Validators.required, (c) => this.validate(c, 'controlName')]]
    });

А потом:

validate(c: FormControl, name) {
    return name === 'controlName' ? {invalid: true} : null;
}

Ответ 6

Не совсем то, что вы хотите, но вы можете динамически создавать валидатор, как в некоторых примерах.

как

typeBasedValidator(controlName: string): ValidatorFn {
  return(control: AbstractControl): {[key: string]: any} => {
     // Your code using controlName to validate
     if(controlName == "something") { 
       doSomething(); 
     } else { 
       doSomethingElse(); 
     }
  }
}

Затем используйте валидатор при создании формы, передав управляющее имя, например