Angular:如果字段以前具有默认值,则将空字符串设置为默认值不会正确更新绑定文本字段

Angular: Setting an emptied string to a default value does not update the bound text field properly if the field previously had the default value

如果我们尝试将其设置为空字符串,我将使用 SET 方法将我的绑定值设置为 'DEFAULT'。绑定的文本输入在每种情况下都能正常运行,除非文本字段已经显示 'DEFAULT' 并且我“select 全部 + 删除”该值。绑定值立即正确设置回 'DEFAULT',但输入字段仍为空。

这是一个显示问题的 stackblitz https://stackblitz.com/edit/angular-a9j8tv?file=src%2Fapp%2Fapp.component.html

如果你有 'DEFAULT' 并且你 select 全部删除,你可以看到输入保持为空,但是绑定到相同值的跨度正确显示新的 re-set 'DEFAULT' 值。

为什么会这样? 有解决办法吗?

问题来自 ngModel。由于 '' 值操纵到 DEFAULT,这是由 ngModel 触发的最新值,ngModel 没有实现值更改以触发新值更改事件。

如何解决;

在比较之前,我已经将变化的值直接赋给了setter中的变量。然后将最小超时设置为 ngModel 可以更新其现有值。 然后当我比较新值并在 '' 的情况下将其更改回 DEFAULT 时,ngModel 实现值更改并触发新值更改事件。这会更新两个表示。

Please find updated stackblitz

固有错误

ngModel directive uses @Input and @Output 获取值并发出更改事件。因此,使用默认更改检测策略将 setter 或 getter 之类的函数绑定到 [ngModel] 之类的指令将触发每个更改检测的函数。

要重现此错误,请在 getter 中插入 console.log,键入一些值并在 <input> 中继续按退格键,然后松开。您可以看到 console.log 消息不断打印。

错误复制:Stackblitz


为什么 'DEFAULT' 没有插入 Ctrl+a+Backspace

如前所述,ngModel 指令使用 @Input 并且相应地 ngOnChanges() hook to fetch any changes to the value from <input> tag. One important thing to note is ngOnChanges() 不会 如果值没有被触发' t 改变了(1).

我们可以尝试将双向绑定 [(ngModel)] 拆分为 [ngModel] 输入和 (ngModelChange) 输出。

export class AppComponent {
  public testString: string;

  onChange(value: string) {
    this.testString = value === '' ? 'DEFAULT' : value;
  }
}
<input type="text" [ngModel]="testString" (ngModelChange)="onChange($event)" />

仍然容易出错:Stackblitz

这里Ctrl+a+Backspace除[=110=以外的任何字符串] 将按预期插入 'DEFAULT'。但是 Ctrl+a+Backspace 'DEFAULT' 会导致空 <input>由于上面讨论的 ngOnChanges() 问题。


解决方案

实现预期行为的一种方法是依赖ngModel指令的ngOnChanges()挂钩来设置值,而是我们自己手动完成.为此,我们可以在 <input> 中使用 Angular template reference variable 并将其发送到组件以进行进一步操作。

export class AppComponent {
  public testString: string;

  public onChange(value: string, inputElem: HTMLInputElement) {
    this.testString = value === '' ? 'DEFAULT' : value;
    inputElem.value = this.testString;
  }
}
<input
  type="text"
  #myInput
  ngModel
  (ngModelChange)="onChange($event, myInput)"
/>

工作示例:Stackblitz

这里的#myInput是模板引用变量。如果这感觉很老套,你需要知道使用 ngModel 来操纵 <input> 本身就叫做 template driven forms。直接操作模板引用是完全合法的。

综上所述,IMO 在需要此类输入操作的情况下,我建议您改用 Angular Reactive Forms。它提供了对输入更精细的控制。


(1) 如果 @InputpreviousValuecurrentValue 不会触发 ngOnChanges()变量的 SimpleChange 对象没有改变。