12

次のことを行う Angular2 ディレクティブに問題があります。

  • ユーザーが「.」を入力したかどうかを検出します。キャラクター。
  • 次の文字も「.」である場合は、重複する「.」を削除します。カーソル位置を「.」の後に移動します。チャー

私は上記の作業を行っていますが、これを ngModel と組み合わせて使用​​すると、モデルが更新されるたびにカーソル位置が最後までジャンプします。

入力:

<input type="text" name="test" [(ngModel)]="testInput" testDirective/>

ディレクティブ:

 import {Directive, ElementRef, Renderer, HostListener, Output, EventEmitter} from '@angular/core';

@Directive({
  selector: '[testDirective][ngModel]'
})
export class TestDirective {


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

  constructor(private el: ElementRef,
    private render: Renderer) { }

  @HostListener('keyup', ['$event']) onInputChange(event) {
    // get position
    let pos = this.el.nativeElement.selectionStart;

    let val = this.el.nativeElement.value;

    // if key is '.' and next character is '.', skip position
    if (event.key === '.' &&
      val.charAt(pos) === '.') {

      // remove duplicate periods
      val = val.replace(duplicatePeriods, '.');

      this.render.setElementProperty(this.el.nativeElement, 'value', val);
      this.ngModelChange.emit(val);
      this.el.nativeElement.selectionStart = pos;
      this.el.nativeElement.selectionEnd = pos;

    }
  }
}

カーソル位置が最後にジャンプすることを除いて、これは機能します。行の削除:

this.ngModelChange.emit(val);

問題が修正され、カーソル位置は正しくなりますが、モデルは更新されません。

誰でもこれに対する解決策を推奨できますか? それとも、問題に対して間違ったアプローチを取っているのでしょうか?

ありがとう

4

3 に答える 3

14

setTimeout() 呼び出しで次の行をラップする必要があります。その理由は、ブラウザーに新しい値をレンダリングする時間を与えてから、新しい値のレンダリング後にリセットされるカーソル位置を変更する必要があるためです。残念ながら、これにより少しちらつきが発生しますが、それを機能させる他の方法を見つけることができませんでした.

setTimeout(() => {
  this.el.nativeElement.selectionStart = pos;
  this.el.nativeElement.selectionEnd = pos;
});
于 2016-12-02T13:04:51.490 に答える
2

私の場合、setTimeout を使用せずに許容できる解決策は次のとおりです。

  1. キーアップ時にモデルを更新しない
  2. focusout の代わりにモデルを更新する

    @HostListener('focusout') focusOut() {
      this.ngModelChange.emit(this.el.nativeElement.value);
    }
    
于 2016-12-02T13:55:03.103 に答える