Angular: доступ к FormControl из директивы

Я хотел бы динамически добавлять валидаторы в свой FormControl с помощью настраиваемой директивы.

@Directive({
    selector: "[idNumber]",
})
export class IdNumberDirective implements OnInit {

    constructor(private formControl: FormControl) { }

    ngOnInit() {
        this.addValidators(this.formControl);
    }

    addValidators(formControl: FormControl) {
        formControl.setValidators(Validators.compose(
            [Validators.required,
            Validators.minLength(3),
            Validators.maxLength(8)
            ]
        ));
    }



<mat-form-field>
    <mat-label>{{label}}</mat-label>
    <input matInput
        [formControl] = "idNumberFormControl"
        [placeholder] = "placeholder"
</mat-form-field>


Мне не нужно ссылаться на nativeElement (через ElementRef).
Я хотел бы сослаться на formControl ...
... и используйте его как таковое:

// HTML with my custom directive 'idNumber' ////////
<custom-input-string
    idNumber 
    [name] = "'idNumber'"
    [label] = "Id Number"
    [placeholder] = "">
</custom-input-string>

// TS ////////
@ViewChild(CustomInputStringComponent) child: CustomInputStringComponent;

ngAfterViewInit() {
    setTimeout(() => {
        this.child.insertIntoForm(this.signupForm);
    }, 0);
}


Любые идеи?
Спасибо всем.

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
11
0
14 604
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы используете NgControl и DI-инъекцию конструктора, у нас может быть директива, применимая к элементам управления формы из реактивных форм в формах formControlName или шаблонов:

Директива:

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

@Directive({
  selector: '[my-directive]'
})
export class MyDirective {
  constructor(private el: ElementRef, private control : NgControl) { }

}

Привет, @Suresh, спасибо за предложение, но мне нужно более подробное объяснение. Смогу ли я это сделать? this.addValidators (this.control); Это сработает? PS: Я не использую и никогда не буду использовать «формы на основе шаблонов».

PaxForce 17.09.2018 13:23

Мы можем получить ссылку на экземпляр элемента управления формой через DI с помощью NgControl. Вы можете получить доступ к методам управления формой, используя этот экземпляр

Suresh Kumar Ariya 17.09.2018 13:28

не могли бы вы обновить свой ответ, добавив еще код ?. Также - в чем смысл «частного el: ElementRef» в вашем предложении?

PaxForce 17.09.2018 13:33
Ответ принят как подходящий

Вот пример использования директивы для добавления валидаторов к вашему элементу управления формой.

Stackblitz

Обратите внимание, что использование этого приведет к потере всех ваших предыдущих валидаторов.

constructor(
  // Get the control directive
  private control: NgControl
) { }
ngOnInit() {
  const abstractControl = this.control.control;
  abstractControl && abstractControl.setValidators([Validators.required]);
}

привет, разве onEvent не запускается каждый раз при изменении значения FormControl? Я имею в виду, разве это событие не срабатывает каждый раз, когда пользователь нажимает любую клавишу, находясь в фокусе FormControl? Нет ли способа проверить и установить эти валидаторы в методе OnInit директивы? Спасибо.

PaxForce 17.09.2018 13:42

Да, он запускается при каждом нажатии клавиши, но условие в функции предотвращает установку валидаторов несколько раз. Это должно быть сделано таким образом, потому что конструктор не знает об элементе управления. Вы также можете использовать ngOnInit (), как в этот stackblitz, который я обновил в своем ответе (потому что это действительно более понятно!)

user4676340 17.09.2018 13:45

Потрясающие! Именно то, что я искал! Спасибо!

PaxForce 17.09.2018 14:51

Этот ответ отлично работает, но я думаю, что основной аспект (использование NgControl вместо FormControl OP) слишком ценен, чтобы оставаться во внешней ссылке (Stackblitz). Я предлагаю поместить эту часть прямо в ответ, как и @Suresh в своем ответе.

Rui Pimentel 14.08.2020 16:46
//TestAnythingsComponent.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { IdNumberDirective } from '../directives/IdNumberDirective.directive';

@Component({
  selector: 'app-test-anythings',
  templateUrl: './test-anythings.component.html',
  styleUrls: ['./test-anythings.component.css'],
  providers:[IdNumberDirective]
})
export class TestAnythingsComponent implements OnInit {
  testForm: FormGroup;

  constructor(fb: FormBuilder, IdNumberDirective : IdNumberDirective) { 
    this.testForm = fb.group({
      idNumberFormControl : new FormControl(null,
          Validators.compose([
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(8),
          IdNumberDirective.customValidator()
          ])
        ),
    })
  }
}

//IdNumberDirective.ts

import { Directive, OnInit } from '@angular/core';
import { Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';

@Directive({
  selector: '[idNumber]'
})
export class IdNumberDirective implements OnInit {

  constructor() {

  }

  ngOnInit() {

  }

  customValidator(): ValidatorFn {
    Validators.nullValidator
    return (control: AbstractControl): ValidationErrors | null => {

      //any condition to check control value
      if (control.value != "Sachin") {
        //return key value pair of errors
        return { "customError": { inValid: true, errMsg: 'Invalid Value' } };
      }
      return null;
    }
  }
}


//test-anythings.component.html

    <form [formGroup] = "testForm">
      <input idNumber formControlName = "idNumberFormControl" />
      <div *ngIf = "testForm.get('idNumberFormControl').invalid && testForm.get('idNumberFormControl').errors.customError.inValid"
        style = "color:red">
        {{testForm.get('idNumberFormControl').errors.customError.errMsg}}
      </div>
    
      <button type = "submit">submit</button>
    </form>

Уважаемый Сачин, не могли бы вы добавить комментарий к вашему коду, чтобы облегчить понимание вашего подхода?

Artem 17.09.2018 15:45

Привет, Артем, посмотри на мое решение выше, пожалуйста, введите «Sachin», чтобы сообщение об ошибке исчезло, я старался изо всех сил, я новичок в angular. Спасибо.

Sachin 17.09.2018 17:03

Другие вопросы по теме