简体   繁体   中英

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.

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.

In numberDirective I used 'input' event because keypress, keydown and keyup not working 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.

Look component in stackblitz ;

Can you help me with my problem?

You should replace your input handler by a keydown handler. 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.

@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.

EDIT : You mentionned you cannot use the keydown handler, sorry.

I managed to get it to work with the oninput handler on the the <input> element and I removed your directive on the input:

<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 .

Hope that helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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