简体   繁体   English

Angular 6 event.stopPropagation()在指令中不起作用(模板驱动形式已经接受event.data)

[英]Angular 6 event.stopPropagation() not working in directive (template-driven form takes event.data already)

I am trying to make a citizenNumber component to use in forms. 我正在尝试使公民编号组件在表单中使用。 It implements ControlValueAccessor for ngModel. 它为ngModel实现ControlValueAccessor。

export class CitizenNumberComponent implements ControlValueAccessor {
    private _value: string;
    @Input() placeholder = '';
    @Input() required = true;

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

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

    // registers 'fn' that will be fired when changes are made
    // this is how we emit the changes back to the form
    registerOnChange(fn: any): void {
        this.propagateChange = fn;
    }

    // not used, used for touch input
    registerOnTouched(fn: any): void { }

    // this is the initial value set to the component
    writeValue(value: string): void {
        if (value) {
        this._value = value;
        }
    }

    // the method set in registerOnChange to emit changes back to the form
    propagateChange = (_: any) => { };
    }

I make a NumberDirective to restrict input except 0-9 digits. 我制定了一个NumberDirective来限制除0-9数字之外的输入。

In numberDirective I used 'input' event because keypress, keydown and keyup not working android chrome. 在numberDirective中,我使用了'input'事件,因为keypress,keydown和keyup无法在android chrome中运行。

@Directive({
    selector: 'input[jhiNumbersOnly]'
})
export class NumberDirective {
    private specialKeys: Array<string> = ['Backspace', 'Delete', 'Insert', 'Tab', 'End', 'Home', 'ArrowRight', 'ArrowLeft'];

    @HostListener('input', ['$event']) onInput(event) {
        const key = event['data'];
        // Allow Backspace, tab, end, and home keys
        if (this.specialKeys.indexOf(key) !== -1) {
            return;
        }
        const initalValue = event.target['value'];
        event.target['value'] = initalValue.replace(/[^0-9]*/g, '');
        if (initalValue !== event.target['value']) {
            event.stopPropagation();
        }
    }
}

Finally, everything works but altough event has stopped, the model takes the value. 最后,一切正常,但所有事件已停止,该模型采用了该值。

As an example, my input maxlength is 11. after 10 number enter, if some key entered (except 0-9) form will be validate. 例如,我输入的最大长度为11。输入10个数字后,如果输入的某些键(0-9除外)将是有效的。

Look component in stackblitz ; stackblitz中查看组件;

Can you help me with my problem? 你能帮我解决我的问题吗?

You should replace your input handler by a keydown handler. 您应该用keydown处理程序替换input处理程序。 Then if the key is good, do nothing, otherwise, prevent the event from happening. 然后,如果密钥是好的,则什么也不做,否则,防止事件发生。

The problem is that if you listen to the input event, it will be too late, the ngModel will have been updated, so you have to listen to the keydown event and filter it appropriately. 问题是,如果您监听输入事件,那将为时已晚, ngModel将被更新,因此您必须监听keydown事件并对其进行适当的过滤。

@HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) {
  if (this.specialKeys.indexOf(e.key) !== -1 || new RegExp(/[0-9]/g).test(e.key)) {
      return;
  }
  e.preventDefault();
}

I tested this code in your stackblitz demo and it works. 我在您的stackblitz演示中测试了此代码,并且可以正常工作。

EDIT : You mentionned you cannot use the keydown handler, sorry. 编辑 :您提到您不能使用keydown处理程序,抱歉。

I managed to get it to work with the oninput handler on the the <input> element and I removed your directive on the input: 我设法使其与<input>元素上的oninput处理程序一起使用,并删除了输入上的指令:

<div class = "form-group">
  <label class = "form-control-label label-color" for = "citizenNumber">Citizen Number
  </label>
  <input type = "text" 
          class = "form-control input-css" 
          name = "citizenNumber"
          id = "citizenNumber"
          #citizenNumber="ngModel"
          oninput="this.value = this.value.replace(/[^0-9]/g, '');"
          [(ngModel)] = "value"
          [placeholder] = "placeholder"
          minlength = "11"
          maxlength = "11"
          [required] = "required">
  <div *ngIf = "citizenNumber.invalid && (citizenNumber.dirty || citizenNumber.touched)"
      class = "form-text text-danger">
      <small *ngIf = "citizenNumber.errors.required">This field is required.</small>
      <small *ngIf = "citizenNumber.errors.minlength">This field must be 11 characters.</small>
      <small *ngIf = "citizenNumber.errors.invalidTc">This is not a citizen number</small>
  </div>
</div>

Here is an updated Stackblitz . 这是更新的Stackblitz

Hope that helps! 希望有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM