Получите доступ к FormControl из компонента пользовательской формы в Angular

У меня есть пользовательский компонент управления формой в моем приложении Angular, который реализует интерфейс ControlValueAccessor.

Однако я хочу получить доступ к экземпляру FormControl, связанному с моим компонентом. Я использую реактивные формы с помощью FormBuilder и обеспечивая управление формой с помощью атрибута formControlName.

SO, как мне получить доступ к экземпляру FormControl изнутри моего настраиваемого компонента формы?

Ответ 1

Это решение родилось из обсуждение в репозитории Angular. Пожалуйста, не забудьте прочитать его или даже лучше участвовать, если вы заинтересованы в этой проблеме.


Я изучил код директивы FormControlName, и это вдохновило меня написать следующее решение:

@Component({
  selector: 'my-custom-form-component',
  templateUrl: './custom-form-component.html',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: CustomFormComponent,
    multi: true
  }]
})
export class CustomFormComponent implements ControlValueAccessor, OnInit {

  @Input() formControlName: string;

  private control: AbstractControl;


  constructor (
    @Optional() @Host() @SkipSelf()
    private controlContainer: ControlContainer
  ) {
  }


  ngOnInit () {

    if (this.controlContainer) {
      if (this.formControlName) {
        this.control = this.controlContainer.control.get(this.formControlName);
      } else {
        console.warn('Missing FormControlName directive from host element of the component');
      }
    } else {
      console.warn('Can\'t find parent FormGroup directive');
    }

  }

}

Я вставляю родительский FormGroup в компонент, а затем получаю от него конкретный FormControl, используя имя управления, полученное посредством привязки FormControlName.

Однако следует иметь в виду, что это решение специально предназначено для использования, где директива FormControlName используется для элемента хоста. В других случаях это не сработает. Для этого вам нужно добавить дополнительную логику. Если вы считаете, что это должно быть адресовано Angular, обязательно посетите обсуждение.

Ответ 2

Использование formControlName в качестве входного параметра не работает при связывании через директиву [formControl].

Вот решение, которое работает в обоих направлениях без каких-либо входных параметров.

export class MyComponent implements AfterViewInit {

  private control: FormControl;

  constructor(
    private injector: Injector,
  ) { }

  // The form control is only set after initialization
  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      this.control = ngControl.control as FormControl;
    } else {
      // Component is missing form control binding
    }
  }
}

Ответ 3

Поскольку @Ritesh уже записал в комментарии, вы можете передать управление формой как привязку ввода:

<my-custom-form-component [control]="myForm.get('myField')" formControlName="myField">
</my-custom-form-component>

И затем вы можете получить экземпляр элемента управления внутри своего настраиваемого компонента формы следующим образом:

@Input() control: FormControl;

Ответ 4

Для тех, кто приезжает сюда в 2019 году, с Angular 6/7+, решение, которое не выдает предупреждение об устаревании, - это решение, описанное в этом ответе:

fooobar.com/info/14214332/...

Для получения более подробной информации смотрите эту презентацию, как описано выше.