首页 > 解决方案 > 绑定到 ngModel 的管道(纯或不纯)中的力变化检测

问题描述

我将 ngModel 值绑定到角度百分比管道,更新 ngModelChange 并将 updateOn 设置为模糊。它工作得很好,除非再次输入相同的值。再次输入相同的值时,管道不会检测到更改,并且该值显示为小数而不是百分比。我曾尝试将百分比管道重新创建为不纯管道,但这不起作用。即使值与以前的值相同,如何强制管道检测更改?

尝试让管道返回WrappedValue.wrap(this._latestValue)

尝试this._ref.detectChanges()在更改功能中运行

<input placeholder="Percentage" type="text" 
       [ngModel]="account.percentage | percent: '1.0-2'"
       (ngModelChange)="updateAssignments($event)" 
       [ngModelOptions]="{updateOn:'blur'}" class="ta-r" />
updateAssignments($event) {
    const cleanEvent = Number($event.replace(/[^\d.]/g, ''));
    account.percentage = (cleanEvent / 100);
}

期望值以百分比格式显示。重新输入后显示十进制值。

我的 Stackblitz 代码

标签: angularangular6angular-pipeangular2-changedetectionangular-changedetection

解决方案


在尝试找到合适的解决方案时,我设法强制纯currency管道以相同的值重新执行(这里是演示)。但这并没有解决问题,因为即使管道重新执行,它最终也会返回相同的结果。因为该结果被绑定到ngModel 实现ngModel中的@Input钩子[ngModel]="account.percentage | percent: '1.0-2'" ngOnChanges,不会更新输入元素视图值。

这是(取自来源)如何ngModel捕获更改和更新值/视图。

@Input('ngModel') model: any;
...

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);
    this.viewModel = this.model;
  }
}

这是执行isPropertyUpdated

export function isPropertyUpdated(changes: { [key: string]: any }, viewModel: any): boolean {
  if (!changes.hasOwnProperty('model')) return false;
  const change = changes['model'];

  if (change.isFirstChange()) return true;
  return !looseIdentical(viewModel, change.currentValue);
}

// https://github.com/angular/angular/blob/53212db3ed48fe98c0c0416ae0acee1a7858826e/packages/core/src/util/comparison.ts#L13
export function looseIdentical(a: any, b: any): boolean {
  return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b);
}

因为 inside 没有变化model返回changes: SimpleChanges isPropertyUpdatedfalse 并且视图没有更新。

所以我尝试按照hacky解决方法从头开始重新初始化输入并且它有效:)

我在输入上放置了一个虚拟变量来显示/隐藏元素;

<input 
  *ngIf="dummy"
  placeholder="Percentage" 
  type="text" 
  [ngModel]="account.percentage | percent: '1.2-2'"
  (ngModelChange)="updateAssignments($event)"
  [ngModelOptions]="{updateOn:'blur'}"
  class="ta-r"
/>

并且每当ngModelChange发射输入被隐藏并立即显示

dummy = true;

constructor(private cdRef: ChangeDetectorRef){}

updateAssignments($event) {
  const cleanEvent = Number($event.replace(/[^\d.]/g, ''));
  this.account.percentage = (cleanEvent / 100);
  this.dummy = false;
  this.cdRef.detectChanges();
  this.dummy = true;
  this.cdRef.detectChanges();
  console.log("account.percentage:", this.account.percentage);
}

==>>>这是一个工作演示<<<==


推荐阅读