angular - (ngModelChange) 不会更新特定输入的 UI

标签 angular typescript angular2-ngmodel

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

当用户输入一个值时,我希望在四舍五入后显示该值,然后将更新后的值存储在 ts 文件中的支持模型上。

使用 Angular 管道对此效果不佳,因为单向管道和更新的值不会反射(reflect)在模型上。

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

<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 属性已更新,但屏幕仍然显示旧值?

感谢您的帮助!

最佳答案

首先仔细查看 ngModel directive API ,您将看到 ngModel@Input binding,它接受一些值作为 model 变量。在初始化 ngModel 时隐式控制它 creates FormControl

public readonly control: FormControl = new FormControl();

更新 model 值的魔力发生在 ngOnChanges hook 处,这样它将 View 值与 model 值同步。如果你仔细观察 ngOnChanges 钩子(Hook),你会发现它验证输入并应用其他检查,然后它严格检查 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}); 
    });
}

但是,为了实现这一点,Angular 应该在更改检测周期中识别更改。而且,由于我们没有更改模型,因此它不会触发 ngOnChanges Hook :

enter image description here

到目前为止我解释的是API部分。让我们回到问题上来。

尝试下面的 snippet in stackblitz ,这就是我们的期望。输入值更改时,应将该值设置为 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 用作单向绑定(bind)。预期的行为是,分配给 model.rate 的任何值都应反射(reflect)在 input 中。让我们尝试输入 1.1,您将看到它向我们显示值 1.1。现在尝试输入 1.2,结果为 1。想知道为什么吗?但 model.rate 绑定(bind)肯定会正确更新。 同样检查 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 绑定(bind)忽略,并显示在 input 内> 字段。

检查 4.64.8 工作正常。为什么?逐步分解

  1. 类型 4 => model.rate 变为 4
  2. 输入 4. => model.rate 保持 4
  3. 类型 4.6 => model.rate 变为 5

在这里,当您在文本框中输入 4.6 时,Math.round 值将变为 5。这是 model.rate(ngModel) 值的更改,并会导致 input 字段值的更新。

现在再次开始阅读答案,最初解释的技术方面也应该很清楚。

Note: While reading an answer follow the links provided to snippet, it may help you understand it more precisely.

<小时/>

要使其正常工作,您可以尝试在 blur/change 上更新您的字段,其中此事件在 fields 之外的焦点上触发,例如 Sid's answer 。它之所以有效,是因为当字段聚焦时您将更新模型一次。

但是它只能工作一次。为了不断更新,我们可以这样做:

this.model.rate = new String(Math.round(value));

每次我们舍入我们的值时,这都会产生一个新的对象引用。

Snippet in Stackblitz

关于angular - (ngModelChange) 不会更新特定输入的 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53427571/

相关文章:

Angular 4 不适用于 Tizen 智能电视

reactjs - 是否可以通过使用 HOC(高阶组件)在类组件中使用 React Hooks?

typescript - Vue 和 Typescript : Image imports not found

angular - 在没有相应 [ngModel] 的情况下使用 (ngModelChange)

forms - Angular 2 : disable button if there are changes in form

angular - 无法使用组件@ncstate/sat-popover 绑定(bind)到属性 'satPopoverAnchorFor'

meteor - 提供 '--isolatedModules' 标志时无法编译 namespace

Angular2 选择了带有对象的选项

angular - http服务缓存