(ngModelChange)不会为特定输入更新UI

时间:2018-11-22 09:23:24

标签: angular angular2-ngmodel

我有一个输入字段,用户可以在其中输入某物的价格。

当用户输入值时,我希望将其四舍五入后再显示,然后将更新后的值存储在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属性得到了更新,但屏幕为何仍显示旧值?

感谢您的帮助!

4 个答案:

答案 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钩子:

enter image description here

到目前为止,我解释的是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.rate4.6会得到5个完美的结果。

让我们按照上面的示例进行分解,当您尝试输入4.8时会发生什么。

  1. 类型1.1 => model.rate变为1
  2. 类型1 => model.rate保持1.
  3. 类型1 => model.rate保持1.1

最终,当您键入11.1时,模型值将保持1.2,因为我们的值为1。由于它不是更新Math.round的值,因此您进一步输入的任何内容都将被model.rate绑定忽略,并显示在ngModel字段中。

检查input4.6正常运行。为什么?明智地将其分解

  1. 类型4.8 => model.rate变为4
  2. 类型4 => model.rate保持4.
  3. 类型4 => model.rate 成为 4.6

在此处,当您在文本框中输入5时,4.6的值将变为Math.round5(ngModel)值的更改将导致model.rate字段值的更新

现在再次开始阅读答案,最初说明的技术方面也将被清除。

  

注意:阅读答案时,请按照提供给摘要的链接进行操作,   可以帮助您更准确地理解它。


要使其正常工作,您可以尝试更新input / blur上的字段,其中此事件会引起change之类的焦点,例如Sid's answer。之所以奏效,是因为您将重点放在领域上一次更新了模型。

但是,它只能运行一次。为了保持不断更新,我们可以做一些技巧:

fields

这将在每次取整值时产生一个新的对象引用。

Snippet in Stackblitz

答案 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 );
}