web-dev-qa-db-ja.com

Angular2キーアップイベントの更新ngModelカーソル位置が最後までジャンプします

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

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

上記の作業を行っていますが、これを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);

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

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

ありがとう

8
conor

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

setTimeout(() => {
  this.el.nativeElement.selectionStart = pos;
  this.el.nativeElement.selectionEnd = pos;
});
11

次のように setSelectionRange() で受け入れられた回答で提案されているように、setTimout()やちらつきなしでカーソルの位置を変更できます。

this.el.nativeElement.setSelectionRange(position, position, 'none');

2
metodribic

私の場合、setTimeoutを使用しない場合の許容可能な解決策は次のとおりです。

  1. キーアップ時にモデルを更新しない
  2. 代わりにフォーカスアウトでモデルを更新します

    @HostListener('focusout') focusOut() {
      this.ngModelChange.emit(this.el.nativeElement.value);
    }
    
2
conor