一尘不染

强制输入值(Angular)

javascript

我有以下输入

<input type="number" [ngModel]="inputValue" (ngModelChange)="handleChange($event)"/>

我试图强制输入保持小于或等于手动。使用方法handleChange

export class AppComponent {

  inputValue: number = 0;


  handleChange($event: any) {
    if ($event > 100) {
      this.inputValue = 100;
    }
  }
}

它仅在我第一次输入高于 100 的第一个输入时才有效,但在那之后我就不行了。

我的理解是当没有值更新时 DOM 不会更新。

例如,我可以使用其他方法使用@ViewChild 来解决这个问题,但我更感兴趣的是了解它是如何工作的以及角度如何处理这个特定的用例


阅读 79

收藏
2022-07-26

共1个答案

一尘不染

解决办法是引入双向绑定,让你的属性和html值同步。在将属性设置为 100之前,您还需要强制进行更改检测。

Stackblitz:https ://stackblitz.com/edit/angular-ivy-upykps?file=src/app/app.component.ts

这两个步骤都是更改检测器每次都检测到属性更改所必需的,只有这样它才会使用您的属性值更新 html 值。

两种方式的绑定是用香蕉盒[(🍌)]符号完成的。

ChangeDetectorRef可注入服务强制进行更改检测。

<input type="number" [(ngModel)]="inputValue" (ngModelChange)="handleChange($event)"/>
  inputValue: number = 0;

  constructor(private cd: ChangeDetectorRef){};

  handleChange($event: any) {
    this.cd.detectChanges();
    if ($event > 100) {
      this.inputValue = 100;
    }
  }

我知道这有点不直观,但它与变化检测器如何检测变化有关。如果你真的想理解它,我建议debugger在你的函数开头添加一行并逐步完成。

我将解释你设置它的方式发生了什么:

html 值通过数据绑定设置为 0,并且更改检测器注意到该属性当前为 0。在每个点击事件中,更改检测在回调之后运行。ngModelChange因此,第一次将属性设置为 100 时,更改检测器会看到 - 哦,是的,属性曾经是 0,现在是 100,发生了更改 - 它设置了一个标志,导致 html 更新为新值,并指出该属性当前为 100。

问题是你从来没有改变过inputValue100 - 所以每次你将它设置为 100 - 变化检测器都看不到任何变化。它永远不会再次更新 html。

使用双向绑定,每当 html 值更改时属性都会更新 - 这发生 ngModelChange. 但这不会更新变化检测器的状态!当我们从小于 100 到大于 100 时它会起作用,但是如果我们继续传递更多大于 100 的数字,它将不会被重置。那是因为变化检测是在之后 ngModelChange运行的,在变化检测器可以看到更大的值之前,我们实际上将较大的值覆盖为 100。我们遇到了同样的问题 - 更改检测器每次都会看到 100,并且不会尝试更新 html。

您需要强制更改检测,以便更改检测器可以记下该属性已更改为这个较大的值。然后将属性设置为 100 后,它会看到 - 是的,属性曾经是这个更大的值,现在是 100 - 它设置了触发 DOM 更新的“已更改”标志。

用户将 html 从 100 更改为 101 的示例:

更改检测器会在每次更改检测时记录当前状态,但不会在数据绑定期间记录。仅当更改检测器发现更改时才会触发 DOM 更新。

Initial State
ACTUAL
html value: 100
property: 100
CHANGE DETECTOR
property: 100

User changes html value to 101
ACTUAL
html value: 101
property: 100
CHANGE DETECTOR
property: 100

Round bracket data binding updates property
ACTUAL
html value: 101
property: 101
CHANGE DETECTOR
property: 100

handleChange calls ChangeDetectorRef.detectChanges()
ACTUAL
html value: 101
property: 101
CHANGE DETECTOR
property: 100 - CHANGED!
**This is the important part 
the change detector sees that the property changed to 101**

Square bracket data binding attempts to update html because of a change
It's already correct though
ACTUAL
html value: 101
property: 101
CHANGE DETECTOR
property: 101

handleChange changes property to 100
ACTUAL
html value: 101
property: 100
CHANGE DETECTOR
property: 101

change detector detects changes because click event occurred
ACTUAL
html value: 101
property: 100
CHANGE DETECTOR
property: 101 - CHANGED!
**If this was still at 100, no updates would be made. 
There would be a mismatch between property and html value**

Square bracket data binding updates html because of a change
ACTUAL
html value: 100
property: 100
CHANGE DETECTOR
property: 100
2022-07-26