【问题标题】:Angular2 keyup event update ngModel cursor position jumps to endAngular2 keyup 事件更新 ngModel 光标位置跳转到结束
【发布时间】:2017-04-17 08:13:37
【问题描述】:

我遇到了一个 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);

修复问题,光标位置正确,但模型没有更新。

谁能推荐一个解决方案?还是我对问题采取了错误的方法?

谢谢

【问题讨论】:

    标签: angular input directive keyup ngmodel


    【解决方案1】:

    您可以在不使用 setTimout() 的情况下更改光标的位置,并按照setSelectionRange() 接受的答案中的建议进行闪烁,如下所示:

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

    示例:stackblitz

    【讨论】:

    • 嗯,这似乎是最好的解决方案。它完美地工作,而接受解决方案却没有(也许这在撰写本文时不可用)。如果您输入速度过快,您可以克服 setTimeout 并获得意外行为。
    • 由于某种原因设置 selectionStartselectionEnd 不起作用,因此您的建议很棒。不知道为什么其他人不起作用(它们被正确读取并用作 setSelectionRange() 的参数,但 setting 为它们设置一个值不会将愚蠢的标记推到正确的位置。
    • 对我来说在 Angular 8 中不起作用,我仍然必须将函数包装在 setTimeout() 中。
    • @George 我在答案中添加了stackblitz,您可以在其中看到此解决方案在 Angular 8 中有效
    • @metodribic 我不再从事那个项目,所以我无法测试,但它是从一个指令内部完成的,该指令做了一些其他事情,包括 ngModelChange.emit 所以它可能是相关的到那个。
    【解决方案2】:

    就我而言,不使用 setTimeout 的可接受解决方案是:

    1. 不更新 keyup 上的模型
    2. 在焦点输出时更新模型

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

    【讨论】:

      【解决方案3】:

      您需要在 setTimeout() 调用中包含以下行。原因是您需要给浏览器时间来呈现新值,然后才能更改光标位置,在新值呈现后重置。不幸的是,这会导致一点点闪烁,但我无法找到任何其他方法使其工作。

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

      【讨论】:

      • 我可以确认这确实有效,并且闪烁不是很明显。这是一个可以接受的解决方案。但是,我希望在不使用 setTimeout 的情况下找到解决方案。
      • 但是当我快速输入时,光标会转到以前的位置并导致问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 2010-10-17
      • 1970-01-01
      相关资源
      最近更新 更多