次のことを行う必要がある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);
問題を修正し、カーソル位置は正しいですが、モデルは更新されません。
誰かがこれに対する解決策をお勧めできますか?それとも私は問題に対して間違ったアプローチを取っているのでしょうか?
ありがとう
SetTimeout()呼び出しでは、次の行を折り返す必要があります。その理由は、新しい値をレンダリングする時間をブラウザに与えてから、新しい値のレンダリング後にリセットされるカーソル位置を変更する必要があるためです。残念ながら、これにより少しちらつきが発生しますが、それを機能させる他の方法を見つけることができませんでした。
setTimeout(() => {
this.el.nativeElement.selectionStart = pos;
this.el.nativeElement.selectionEnd = pos;
});
次のように setSelectionRange() で受け入れられた回答で提案されているように、setTimout()やちらつきなしでカーソルの位置を変更できます。
this.el.nativeElement.setSelectionRange(position, position, 'none');
私の場合、setTimeoutを使用しない場合の許容可能な解決策は次のとおりです。
代わりにフォーカスアウトでモデルを更新します
@HostListener('focusout') focusOut() {
this.ngModelChange.emit(this.el.nativeElement.value);
}