【问题标题】:Force change detection in pipe (pure or impure) bound to ngModel绑定到 ngModel 的管道(纯或不纯)中的力变化检测
【发布时间】:2019-05-03 16:15:12
【问题描述】:

我将 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);
}

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

My Stackblitz Code

【问题讨论】:

  • 我不明白为什么它不起作用......如果管道是纯净的有什么关系?相同的输入相同的输出对吗?管道刚刚停止工作了吗?
  • 嘿mah koreh gever?如果它是纯的,它只在输入更改时运行管道,如果它不纯,它运行每个更改检测周期。
  • 我已经解决这个问题好几天了。有些东西很可疑。我的情况完全一样,除了我使用 (blur) 并有一个条件管道: 你知道怎么做吗这份工作?
  • @verynear 将接受的答案设置为 ysf,如果您有时间并且该解决方案适合您。

标签: angular angular6 angular-pipe angular2-changedetection angular-changedetection


【解决方案1】:

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

这是(取自sourcesngModel 如何捕获更改和更新值/视图。

@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;
  }
}

这是isPropertyUpdatedimplementation

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

因为changes: SimpleChanges 内的model 没有变化,isPropertyUpdated 返回 false 并且视图未更新。

所以我尝试按照 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);
}

==>>> here is a working demo

【讨论】:

  • 这看起来很有希望!可能不是让它工作的最纯粹的方法,但如果它有效,它就有效! :D 今天下午试试!
  • 是的!工作!我在这个 PM 将版本发送给 QA,看看是否有任何问题,但初始测试很好。聪明的解决方法,得到我想要的行为!
【解决方案2】:

它只会在您模糊输入后更新,因为您将 ngModelOptions 设置为仅在模糊时更新 :)

删除它应该可以解决问题。

【讨论】:

  • 如果没有updateOn: blur,它会在用户仍在键入时尝试添加百分号。但是是的,我只是想看看,即使默认(updateOn change)问题仍然存在
  • 很难像这样调试,你能提供类似代码要点的东西吗?还是stackblitz.com 示例?
  • 见上面的 stackblitz 链接。它工作正常,直到您尝试连续两次输入相同的值
【解决方案3】:

试试[ngModelOptions]="{updateOn:'change'}"

https://stackblitz.com/edit/angular-6-material-starter-rdxhte?file=src/app/hello.component.html

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

【讨论】:

  • 正如另一个答案中提到的,on change 的行为确实不可用,只要用户输入一个数字,% 就会被添加。因此,例如键入 41 最终会成为一个奇怪的值,例如 4.00%1,这是行不通的。此外,在 64 中复制粘贴会触发报告的管道未应用问题。 (也许是不脏检测或类似的东西?)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
  • 1970-01-01
  • 2011-07-25
  • 2017-01-10
  • 2016-07-20
  • 1970-01-01
  • 2018-11-27
相关资源
最近更新 更多