输入时 ngModelChange 无限循环
ngModelChange infinite loop on input
我有一个 html 这样的:
<ng-template [ngSwitchCase]="'textbox'">
<input *ngIf="setting.type==='number'"
[step]="setting.step"
[formControlName]="formName"
[id]="formName"
[type]="setting.type"
[placeholder]="setting.placeholder"
[title]="setting.description"
(ngModelChange)="onChange($event)">
</ng-template>
在控制器上我有函数 onChange:
onChange(newValue: string) {
if (newValue === undefined)
return;
this.form.get(this.formName).setValue(<any>parseFloat(newValue));
}
当我调试这个 onChange 函数的调用时,我注意到它仍在调用,但我真的不知道为什么。我有一个无限循环。
我的 angular 个包裹:
"@angular/animations": "8.2.7",
"@angular/cli": "8.3.5",
"@angular/common": "8.2.7",
"@angular/compiler": "8.2.7",
"@angular/core": "8.2.7",
"@angular/forms": "8.2.7",
"@angular/platform-browser": "8.2.7",
"@angular/platform-browser-dynamic": "8.2.7",
"@angular/router": "8.2.7",
"@babel/polyfill": "7.6.0",
你知道我的代码可能有什么问题吗?
可能是因为在onChange函数中设置了输入值,再次改变了输入值,又调用了onChange。这将无限继续下去。
在需要时将其转换为数字,而不是将字符串解析为数字然后将其设置为不需要的控件。
parseFloat(this.form.get(this.formName).value)
或
+this.form.get(this.formName).value
在这种情况下,不需要每次更改值时都将其解析为数字,而是在需要时解析。
您可以使用上述行之一将每次更改的输入解析为数字,但不要再次将其设置为同一控件。
onChange(newValue: string) {
parseFloat(this.form.get(this.formName).value)
}
ControlValueAccessor 方法
见 to a similar question. I know that question is not exactly the same, but it appears to be a solid approach as far as I can tell. Instead of using the ngModelChange
event, that answer suggests wrapping the input component and implementing a custom ControlValueAccessor
- see the documentation。
这里是StackBlitz example这种方法。但是,它的行为似乎与 blur
事件一样,因此与下面的方法相比,这种情况下的 ControlValueAccessor
可能有点矫枉过正。
模糊事件方法
另一种选择是在您的输入中使用 blur
事件。您不必在每次更改时都尝试更新该值,而只需在用户离开控件时更新该值(解析为 float
)。类似于:
HTML
<ng-template [ngSwitchCase]="'textbox'">
<input *ngIf="setting.type==='number'"
[step]="setting.step"
[formControlName]="formName"
[id]="formName"
[type]="setting.type"
[placeholder]="setting.placeholder"
[title]="setting.description"
(blur)="onBlur()"> <!-- this line -->
</ng-template>
组件 TypeScript
onBlur() {
const value = this.form.get(this.formName).value;
this.form.get(this.formName).setValue(<any>parseFloat(value));
}
Example 我在 StackBlitz 上创建了 blur
方法。
我有一个 html 这样的:
<ng-template [ngSwitchCase]="'textbox'">
<input *ngIf="setting.type==='number'"
[step]="setting.step"
[formControlName]="formName"
[id]="formName"
[type]="setting.type"
[placeholder]="setting.placeholder"
[title]="setting.description"
(ngModelChange)="onChange($event)">
</ng-template>
在控制器上我有函数 onChange:
onChange(newValue: string) {
if (newValue === undefined)
return;
this.form.get(this.formName).setValue(<any>parseFloat(newValue));
}
当我调试这个 onChange 函数的调用时,我注意到它仍在调用,但我真的不知道为什么。我有一个无限循环。
我的 angular 个包裹:
"@angular/animations": "8.2.7",
"@angular/cli": "8.3.5",
"@angular/common": "8.2.7",
"@angular/compiler": "8.2.7",
"@angular/core": "8.2.7",
"@angular/forms": "8.2.7",
"@angular/platform-browser": "8.2.7",
"@angular/platform-browser-dynamic": "8.2.7",
"@angular/router": "8.2.7",
"@babel/polyfill": "7.6.0",
你知道我的代码可能有什么问题吗?
可能是因为在onChange函数中设置了输入值,再次改变了输入值,又调用了onChange。这将无限继续下去。
在需要时将其转换为数字,而不是将字符串解析为数字然后将其设置为不需要的控件。
parseFloat(this.form.get(this.formName).value)
或
+this.form.get(this.formName).value
在这种情况下,不需要每次更改值时都将其解析为数字,而是在需要时解析。
您可以使用上述行之一将每次更改的输入解析为数字,但不要再次将其设置为同一控件。
onChange(newValue: string) {
parseFloat(this.form.get(this.formName).value)
}
ControlValueAccessor 方法
见ngModelChange
event, that answer suggests wrapping the input component and implementing a custom ControlValueAccessor
- see the documentation。
这里是StackBlitz example这种方法。但是,它的行为似乎与 blur
事件一样,因此与下面的方法相比,这种情况下的 ControlValueAccessor
可能有点矫枉过正。
模糊事件方法
另一种选择是在您的输入中使用 blur
事件。您不必在每次更改时都尝试更新该值,而只需在用户离开控件时更新该值(解析为 float
)。类似于:
HTML
<ng-template [ngSwitchCase]="'textbox'">
<input *ngIf="setting.type==='number'"
[step]="setting.step"
[formControlName]="formName"
[id]="formName"
[type]="setting.type"
[placeholder]="setting.placeholder"
[title]="setting.description"
(blur)="onBlur()"> <!-- this line -->
</ng-template>
组件 TypeScript
onBlur() {
const value = this.form.get(this.formName).value;
this.form.get(this.formName).setValue(<any>parseFloat(value));
}
Example 我在 StackBlitz 上创建了 blur
方法。