我有一个输入字段,用户可以在其中输入某物的价格。
当用户输入值时,我希望将其四舍五入后再显示,然后将更新后的值存储在ts
文件的支持模型中。
使用Angular管道不利于此,因为一个方向的管道和更新的值不会反映在模型上。
为了使其双向,我正在执行以下操作:
<input type="text" [ngModel]="model.rate" (ngModelChange)="model.rate=roundRate($event)" name="rate" />
roundDate
函数如下所示
roundRate(value) {
return Math.round(value);
}
现在,当我输入5.6、7.8、9.5等值时,它们都被四舍五入,显示并分别存储在模型上,分别为6、8和10,这是预期的行为。
当我输入2.1、3.4、5.3等时,问题开始。在这种情况下,将调用roundRate
函数,并在四舍五入后返回值。但是屏幕上显示的值仍然是旧值(2.1、3.4、5.3)
我检查了Chrome上的input
元素,发现ng-reflect-model
属性正在更新为预期值(2、3、5)。
<input _ngcontent-c39="" name="rate" type="text" ng-reflect-name="rate" ng-reflect-model="5" class="ng-valid ng-dirty ng-touched">
有人可以解释一下这里发生了什么吗,尽管ng-reflect-model
属性得到了更新,但屏幕为何仍显示旧值?
感谢您的帮助!
答案 0 :(得分:3)
仔细研究ngModel
directive API,您会发现ngModel
是@Input
binding,它接受某些值作为model
变量。在初始化ngModel
时对其进行隐式控制creates FormControl
。
public readonly control: FormControl = new FormControl();
更新model
值的神奇之处在于ngOnChanges
hook,这样可以将视图值与model
值同步。如果仔细查看ngOnChanges
钩子,您会发现它会验证输入并也应用其他检查,然后严格检查ngModel
的值是否确实使用{{1 }}方法。
ngOnChanges-isPropertyUpdated
指令
ngModel
但是要使其成为现实,Angular应该在变更检测周期内识别出变更。由于我们没有更改模型,因此不会触发ngOnChanges钩子:
到目前为止,我解释的是API部分。让我们回到这个问题。
尝试以下snippet in stackblitz,这是我们的期望。输入值更改时,应将其自身设置为ngOnChanges(changes: SimpleChanges) {
this._checkForErrors();
if (!this._registered) this._setUpControl();
if ('isDisabled' in changes) {
this._updateDisabled(changes);
}
if (isPropertyUpdated(changes, this.viewModel)) {
this._updateValue(this.model); // helps to update
this.viewModel = this.model;
}
}
private _updateValue(value: any): void {
resolvedPromise.then(() => {
// set value will set form control
this.control.setValue(value, {emitViewToModelChange: false});
});
}
。
10
不幸的是,它不会以这种方式发生,您会看到,在最初键入任何数字时,它将输入值更改为<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate = 10"
name="rate" />
,随后您将键入的任何内容将继续追加到数字输入中。啊,想知道为什么吗?
让我们再次回到原始问题,
10
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate=roundRate($event)"
name="rate" />
{{model.rate}}
用作一种方式绑定。预期的行为是,分配给ngModel
的任何值都应反映在model.rate
内部。让我们尝试输入1.1,您会看到它显示了我们的值input
。现在尝试输入1.1
,在1.2
中得到1.2个结果。想知道为什么?但是肯定1
绑定会正确更新。
同样,检查model.rate
,4.6
会得到5个完美的结果。
让我们按照上面的示例进行分解,当您尝试输入4.8
时会发生什么。
1.1
=> model.rate变为1
1
=> model.rate保持1.
1
=> model.rate保持1.1
最终,当您键入1
或1.1
时,模型值将保持1.2
,因为我们的值为1
。由于它不是更新Math.round
的值,因此您进一步输入的任何内容都将被model.rate
绑定忽略,并显示在ngModel
字段中。
检查input
,4.6
正常运行。为什么?明智地将其分解
4.8
=> model.rate变为4
4
=> model.rate保持4.
4
=> model.rate 成为 4.6
在此处,当您在文本框中输入5
时,4.6
的值将变为Math.round
。 5
(ngModel)值的更改将导致model.rate
字段值的更新
现在再次开始阅读答案,最初说明的技术方面也将被清除。
注意:阅读答案时,请按照提供给摘要的链接进行操作, 可以帮助您更准确地理解它。
要使其正常工作,您可以尝试更新input
/ blur
上的字段,其中此事件会引起change
之类的焦点,例如Sid's answer
。之所以奏效,是因为您将重点放在领域上一次更新了模型。
但是,它只能运行一次。为了保持不断更新,我们可以做一些技巧:
fields
这将在每次取整值时产生一个新的对象引用。
答案 1 :(得分:1)
对于更清洁的实现,只需使用(change)
@Output
属性和[(ngModel)]
。 roundRate
的实现将更改如下内容:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
model = { rate: null };
roundRate() {
this.model.rate = Math.round(+this.model.rate);
}
}
在模板中:
<input type="text" [(ngModel)]="model.rate" (change)="roundRate()" name="rate" />
PS::仅当您从输入字段blur
{p>
这是您推荐的Sample StackBlitz。
答案 2 :(得分:0)
在Angular更改检测策略中,有助于在UI上反映更改。
请使用以下代码:
步骤1:将ChangeDetectorRef
导入组件
import { ChangeDetectorRef} from angular/core';
步骤2:在构造函数上创建ChangeDetectorRef
的实例。
constructor(private ref: ChangeDetectorRef){
}
步骤3:调用您要更新值的位置。
this.ref.detectChanges();
答案 3 :(得分:0)
我们还可以使用$ event而不是ngModel-来获取其值
component.html
<table>
<tbody>
<tr>
<td colspan="2" style="width:100px;height:38px;"><input type = "text" (change)="enterDirectRowNumberResponse(data,$event.target.value)"></td></tr>
</tbody
</table>
component.ts
enterDirectRowNumberResponse(data,event){
console.log ("Inside enterDirectRowNumberResponse",event)
console.log ("data = ", data );
}