gpt4 book ai didi

javascript - 光标在 ngModelChange Angular/Typescript 上结束时出现问题

转载 作者:行者123 更新时间:2023-12-04 03:41:14 27 4
gpt4 key购买 nike

我的 HTML 输入字段和使用 ngModelChange 的 typescript 组件有问题。我希望能够在任何需要的地方编辑输入值。

例如:

  • 原始输入自动填充为“00:00:00”。我想将其编辑为“01:20:00”。
  • 用我的键盘将光标 (^) 定位到我需要的位置 0^0:00:00
  • 我输入1,结果是“01:00:00^”
  • 如果我想添加 2,我需要再次移动光标,这对我来说是不可取的。

我知道这是一个已知问题,可以通过使用 setSelectionRange 重新设置光标来解决,但是这没有用,因为即使我使用 setSelectionRange(selectionStart, selectionEnd) 和正确的光标值,ngModelChange , 会将光标放回末尾。

我还有一个正则表达式,它在每​​两位数字后应用冒号。

尽管这是我的代码,但我还提供了一个 stackblitz 供您使用:https://stackblitz.com/edit/angular-ivy-adynjf?file=src/app/app.compone

这是我的输入框:

<input
id="value"
type="text"
[ngModel]="changedValue"
(ngModelChange)="formatAndChange($event)"
/>

和我的组件的一部分:

export class AppComponent {
public changedValue: String = "00:00:00";

public formatAndChange(inputValue: string) {
this.changedValue = inputValue;

if (inputValue.length > 8) {
inputValue = inputValue.substr(0, 8);
}
let unformat = inputValue.replace(/\D/g, "");
if (unformat.length > 0) {
inputValue = unformat.match(new RegExp(".{1,2}", "g")).join(":");
}

this.changedValue = new String(inputValue);
}
}

基本上我的问题是,如果我们想要它,应该如何使用这个结构:值会在用户键入时更改并格式化(我们添加冒号以便格式正确),并且光标停留在place(ngModelChange 不会改变光标位置,或者至少我可以让它回到原来的位置)

欣赏它。谢谢!!

最佳答案

这不太正确:

even if I used the setSelectionRange(selectionStart, selectionEnd) with the correct value of the cursor, the ngModelChange, would put the cursor back to the end.

每当通过 JavaScript 更新值时,浏览器会将光标置于输入字段的末尾。与 Angular 无关。

让我们看看当您在输入字段中键入内容时会发生什么。这是一个非常明确的序列:

  1. ngModelChange 触发;
  2. formatAndChange 运行并更新 changedValue;
  3. Angular 的变化检测运行(此时 formatAndChange 方法已完成);
  4. Angular 更新模板中的值,从而更新传递给 ngModel 的值;
  5. ngModel 安排微任务(我将在答案末尾进行解释),它会更新实际的输入元素值。

请注意,当 ngModel 更新时,ngModelChange 甚至不会被触发。

如果您尝试在 formatAndChangesetSelectionRange,它永远不会起作用,因为这是会发生的事情:

  1. changedValue 已更新;
  2. 光标位于输入字段中的预期位置;
  3. ngModel 和随后的输入值被更新,将光标抛到输入的末尾。

要实现此功能,您需要在输入值更新后 调用 setSelectionRange - 所以至少在更改检测完成后调用微任务。这是更新后的代码(请注意,由于数字之间有冒号,这不能完全正确地工作,但我相信您可以自己弄清楚):

import {
AfterViewChecked,
Component,
ElementRef,
ViewChild
} from '@angular/core';

@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewChecked {
public changedValue: String = '00:00:00';

private valueUpdated: boolean;

private selectionStart: number;

private selectionEnd: number;

private selectionDirection: 'forward' | 'backward' | 'none';

@ViewChild('input')
private inputRef: ElementRef<HTMLInputElement>;

public formatAndChange(inputValue: string) {
console.log(inputValue);
const oldChangedValue = this.changedValue;
this.changedValue = inputValue;

if (inputValue.length > 8) {
inputValue = inputValue.substr(0, 8);
}
let unformat = inputValue.replace(/\D/g, '');
if (unformat.length > 0) {
inputValue = unformat.match(new RegExp('.{1,2}', 'g')).join(':');
}
console.log(inputValue);

this.changedValue = new String(inputValue);

this.valueUpdated = oldChangedValue !== this.changedValue;

if (this.valueUpdated && this.inputRef.nativeElement) {
const element = this.inputRef.nativeElement;
this.selectionStart = element.selectionStart;
this.selectionEnd = element.selectionEnd;
this.selectionDirection = element.selectionDirection;
}
}

// This lifecycle hook is called after change detection is complete for this component
ngAfterViewChecked() {
// This method is called VERY often, so we need to make sure that we only execute this logic when truly necessary (i.e. the value has actually changed)
if (this.valueUpdated && this.inputRef.nativeElement) {
this.valueUpdated = false;

// This is how you schedule a microtask
Promise.resolve().then(() => {
// Make sure you update this to deal with colons
this.inputRef.nativeElement.setSelectionRange(
this.selectionStart,
this.selectionEnd,
this.selectionDirection
);
});
}
}
}

微任务

微任务基本上是一些代码,在当前调用堆栈清空后执行。 Javascript 的任务和微任务是 JavaScript 引擎的核心,它们实际上并不那么容易掌握,但理解起来非常有用。

我不知道为什么 Angular 开发人员决定更新微任务中的输入值,一定有他们的原因。

关于javascript - 光标在 ngModelChange Angular/Typescript 上结束时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65992685/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com