Как получить событие ввода от дочернего компонента к директиве родительского компонента

#angular #angular-directive

#angular #angular-директива

Вопрос:

У меня есть директива для преобразования ввода в верхний регистр

 import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[appUpperCase]',
})
export class UpperCaseInputDirective {
  @HostListener('input', ['$event']) onInput(event) {
    console.log("UpperCaseInputDirective::event",event);
    event.target.value = event.target.value.toUpperCase();
    return true;
  }
}
  

Это отлично работает с полями ввода, но теперь я хочу создать пользовательский компонент с некоторым шаблонным кодом вокруг поля ввода

 <div class="form-group-basic">
  <label [for]="internalId">{{label}}</label>
  <mat-form-field floatLabel="always" appearance="outline">
    <input
      [id]="internalId"
      matInput
      [formControl]="formControl"
      (input)="onInput($event)"
    />
    <mat-error *ngIf="formControl.invalid">{{
      getErrorMessage(formControl.errors)
      }}</mat-error>
  </mat-form-field>
</div> 
  

Чтобы получить событие ввода из поля ввода за пределами моего пользовательского компонента, я переслал это событие с помощью EventEmitter

 import { Component, EventEmitter, forwardRef, HostBinding, Input, Output } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { translateErrors } from '../../../translation/service/translation.service';

@Component({
  selector: 'app-input',
  templateUrl: './input.component.html',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputComponent),
      multi: true
    }
  ]
})
export class InputComponent implements ControlValueAccessor {

  @HostBinding('attr.id')
  externalId = '';
  internalId = '';

  @Input()
  formControl: FormControl;

  @Input()
  label: string;

  @Input()
  set id(value: string) {
    this.internalId = value;
    this.externalId = null;
  }

  get id() {
    return this.internalId;
  }

  @Input('value') _value = '';
  onChange: any = () => {};
  onTouched: any = () => {};

  get value():string {
    return this._value;
  }

  set value(value: string) {
    this._value = value;
    this.onChange(value);
    this.onTouched();
  }

  @Output() input: EventEmitter<any> = new EventEmitter();

  control: FormControl;

  constructor() {
    this.control = new FormControl()
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }

  writeValue(value) {
    if (value) {
      this.value = value;
    }
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  getErrorMessage(errors: object): string {
    return translateErrors(errors);
  }

  onInput(event) {
    console.log("inputComponent::onInput",event);
    this.input.emit(event);
  }
}
  

Теперь я пытаюсь дать своему пользовательскому компоненту эту директиву:

 <app-input id="test-input-field" (input)="onInput($event)" [formControl]="test" appUpperCase label="Test" ></app-input>
  

Но директива не вызывается. Когда я ввожу символ, я вижу

 inputComponent::onInput InputEvent {isTrusted: true, data: "d", isComposing: false, inputType: "insertText", dataTransfer: null, …}
customed.component.ts:94 paymentDetailsFormComponen::onInput InputEvent {isTrusted: true, data: "d", isComposing: false, inputType: "insertText", dataTransfer: null, …}
customed.component.ts:94 paymentDetailsFormComponen::onInput InputEvent {isTrusted: true, data: "d", isComposing: false, inputType: "insertText", dataTransfer: null, …}
  

Я вижу событие один раз в компоненте InputField и дважды из моего компонента, но обработчик директивы не вызывается. Как я могу этого добиться?

Комментарии:

1. Возможно, у вас ошибка где-то еще в вашем коде. Он отлично работает в этом стекблите, который я только что собрал.

2. @MikeJ Спасибо за подсказку. На первый взгляд я не вижу никакой разницы между вашим StackBlitz и моим приложением. Я думаю, мне нужно взглянуть на это немного глубже.