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

Yog*_*esh 4 angular2-ngmodel angular

我有一个输入字段,用户可以在其中输入事物的速率。

当用户输入值时,我希望将其四舍五入后再显示,然后将更新后的值存储在ts文件的后备模型中。

使用Angular管道不利于此,因为一个方向的管道和更新后的值不会反映在模型上。

因此,为了使其双向,我正在执行以下操作:

<input type="text" [ngModel]="model.rate" (ngModelChange)="model.rate=roundRate($event)" name="rate" />
Run Code Online (Sandbox Code Playgroud)

roundDate功能看起来像这样

roundRate(value) {
    return Math.round(value);
}
Run Code Online (Sandbox Code Playgroud)

现在,当我输入5.6、7.8、9.5等值时,它们都被四舍五入,显示并分别在模型上存储为6、8和10,这是预期的行为。

当我输入2.1、3.4、5.3等时,问题开始。在这种情况下,该roundRate函数被调用,并在四舍五入后返回值。但是屏幕上显示的值仍然是旧值(2.1、3.4、5.3)

我检查了inputChrome上的元素,发现该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">
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下这里发生了什么吗,尽管ng-reflect-model属性已更新,但为什么屏幕仍显示旧值?

谢谢你的帮助!

Pan*_*kar 6

与在细看开始ngModel指令API,你会看到,ngModel@Input结合它接受一些价值作为model变量。在初始化ngModel控制时,它FormControl隐式创建

public readonly control: FormControl = new FormControl();
Run Code Online (Sandbox Code Playgroud)

更新model值的神奇之处在于ngOnChangeshook,通过这种方式,它可以将视图值与modelvalue 同步。如果仔细看一下ngOnChanges钩子,您会发现它会验证输入并也应用其他检查,然后严格检查ngModel值是否真的使用isPropertyUpdated方法更改了。

ngOnChanges -ngModel指令

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}); 
    });
}
Run Code Online (Sandbox Code Playgroud)

但是要使其实现,Angular应该在变更检测周期内识别出变更。由于我们没有更改模型,因此不会触发ngOnChanges钩子:

在此处输入图片说明

到目前为止,我所解释的是API部分。让我们回到这个问题。

在stackblitz中尝试以下代码片段,这是我们的期望。输入值更改时,应将该值设置为其10自身。

<input type="text" 
  [ngModel]="model.rate" 
  (ngModelChange)="model.rate = 10"
  name="rate" />
Run Code Online (Sandbox Code Playgroud)

不幸的是,这种情况并没有发生,您将看到在初始输入任何数字时,它将把输入值更改为10,随后您将键入的任何内容将继续添加到数字输入中。啊,想知道为什么吗?

让我们再回到原始问题,

<input type="text" 
  [ngModel]="model.rate" 
  (ngModelChange)="model.rate=roundRate($event)"
  name="rate" />
 {{model.rate}}
Run Code Online (Sandbox Code Playgroud)

ngModel用作绑定的一种方式。预期的行为是,分配给的任何值model.rate都应反映在中input。让我们尝试输入1.1,您会看到它显示了我们的价值1.1。现在尝试输入1.2,结果为1.2 1。想知道为什么吗?但可以肯定的是model.rate绑定可以正确更新。类似地,检查4.64.8得到5个效果最佳。

让我们将其分解为上面的示例,当您尝试输入时会发生什么1.1

  1. 类型1 => model.rate变成1
  2. 类型1. => model.rate停留1
  3. 类型1.1=> model.rate停留1

最终当您键入1.11.2模型值保留1以来,我们便会Math.round重视。由于它不是更新model.rate值,因此您输入的任何内容都将被ngModel绑定忽略,并显示在input字段中。

检查4.6,是否4.8完美。为什么?明智地分解它

  1. 类型4 => model.rate变成4
  2. 类型4. => model.rate停留4
  3. 类型4.6=> model.rate 变成 5

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

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

注意:在阅读答案时,请按照摘录中提供的链接进行操作,这可能有助于您更准确地理解它。


为了使它起作用,您可以尝试在blur/ change上更新您的字段,而在该事件上,焦点会fields像这样Sid's answer。之所以奏效,是因为您将重点放在领域上一次更新了模型。

但是它只能工作一次。为了保持不断更新,我们可以采取一些措施:

this.model.rate = new String(Math.round(value));
Run Code Online (Sandbox Code Playgroud)

每当我们舍入我们的值时,这将导致一个新的对象引用。

Stackblitz中的片段

  • 但是,如果我们将像`this.model.rate = new String(Math.round(value));`这样的值进行更改,那么`change / blur`事件肯定会起作用https://stackblitz.com/edit/angular-ngmodelchanges -eg-upzz5p?file = src / app / app.component.ts (2认同)

Sid*_*era 4

为了更简洁的实现,只需使用(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);
  }
}
Run Code Online (Sandbox Code Playgroud)

并在模板中:

<input type="text" [(ngModel)]="model.rate" (change)="roundRate()" name="rate" />
Run Code Online (Sandbox Code Playgroud)

PS:blur只有当您从输入字段中更改该值时,才会更新该值


这是一个StackBlitz 示例供您参考。

  • @SiddAjmera 购买(更改)只能在触发模糊后调用一次。 (2认同)