Можно ли получить собственный элемент для formControl?

У меня есть Angular2 реактивная форма. Я создал formControl и присвоил его полям ввода [formControl]=.... Как я понимаю, он создает ссылку nativeElement <-> formControl.

Мой вопрос: можно ли получить nativeElement для formControl? Я хочу сделать что-то вроде myFormControl.nativeElement.focus()

Ответ 1

Приведенный ниже код не работает с чистой привязкой ngModel, поэтому я провел много экспериментов. Последний, также подтвержденный Максимиллианом Шварцмюллером, должен быть следующим:

@Directive({
    selector: '[ngModel]', // or 'input, select, textarea' - but then your controls won't be handled and also checking for undefined would be necessary
})
export class NativeElementInjectorDirective {
    constructor(private el: ElementRef, private control : NgControl) {
        (<any>control.control).nativeElement = el.nativeElement;
    }
}

Поэтому, если эта директива предоставлена и экспортирована в основной модуль, она присоединит настраиваемое свойство nativeElement ко всему FormControl.

Стыдно не выходить из коробки...

Ответ 2

Я могу поделиться одним ужасным решением, но оно работает для меня.

В реактивных формах мы можем использовать либо

1) FormControlDirective

ц

myControl = new FormControl('')

шаблон

<input type="text" [formControl]="myControl">

или

2) FormControlName

ц

myForm: FormGroup;

constructor(private fb: FormBuilder) {}

ngOnInit() {
  this.myForm = this.fb.group({
    foo: ''
  });
}

шаблон

<form [formGroup]="myForm">
  <input type="text" formControlName="foo">
</form>

Итак, для этих директив я мог бы написать некоторый патч, например

1) FormControlDirective

const originFormControlNgOnChanges = FormControlDirective.prototype.ngOnChanges;
FormControlDirective.prototype.ngOnChanges = function() {
  this.form.nativeElement = this.valueAccessor._elementRef.nativeElement;
  return originFormControlNgOnChanges.apply(this, arguments);
};

2) FormControlName

const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;
FormControlName.prototype.ngOnChanges = function() {
  const result =  originFormControlNameNgOnChanges.apply(this, arguments);
  this.control.nativeElement = this.valueAccessor._elementRef.nativeElement;
  return result;
};

После этого мы можем легко получить доступ к собственному элементу с FormControl экземпляром

1) FormControlDirective

focusToFormControl() {
  (<any>this.myControl).nativeElement.focus();
}

2) FormControlName

focusToFormControlName(name) {
  (<any>this.myForm.get(name)).nativeElement.focus();
}

Пример плунжера

Ответ 3

В ответ baHI добавлено незначительное исправление (перемещена логика в OnInit). Ошибка, упомянутая в комментариях, вероятно, связана с изменениями в формах. Этот ответ для "@angular/forms": "~ 7.1.0",

    @Directive({
      selector: '[ngModel]'
    })
    export class NativeElementInjectorDirective implements OnInit {
        constructor (private el: ElementRef, private control : NgControl) {}

        ngOnInit(){
          (this.control.control as any).nativeElement = this.el.nativeElement;
        }
    }

Ответ 4

Да, вы должны написать директиву с помощью [formControl], [formControlName]. Полный пример:

import { Directive, ElementRef } from "@angular/core";
import { NgControl } from '@angular/forms';

@Directive({
   selector: '[formControl], [formControlName]'
})
export class ControlErrorsDirective {
    get control() {
       return this.controlDir.control;
    }

    constructor(
        private controlDir: NgControl,
        private host: ElementRef<HTMLFormElement>) {
    }
    ngOnInit() {
        console.log(this.host.nativeElement);
    }
}

и в вашем html просто используйте formControlName следующим образом: <input formControlName='name'/>