当绑定到的值不更改时强制进行更改检测 [英] Forcing change detection when value bound to doesn't change

查看:38
本文介绍了当绑定到的值不更改时强制进行更改检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个组件可以对输入控件中的更改做出反应,并通过删除某些字符来对其重新格式化.设置完成后,备份字段中存储的值可能会更改或不会更改.在第一种情况下,一切正常,但是如果删除的字符映射到先前的值,则不会检测到任何更改,并且组件也不会更新.这将导致包括可移动字符在内的值停留在输入框中.

I have a component that reacts to a change in input control and reformats it by removing certain characters. When setting is done, the value stored in the backing field may change or not. In the first case, everything works but if the removed character maps to the previous value, there's no change detected and the component doesn't update. That leads to the value including the removable character stays in the input box.

如何强制通过 [(ngModel)] 绑定到后备字段的输入框实际更新将其输入值更改为 get prop()服务的值>设施?

How can I force an input box bound via [(ngModel)] to a backing field to actually update changing it's entered value to the one served by get prop() facility?

export class RowConfig {
  constructor(public amount = 0, ...) { }

  get rendition() {
    let output = "";
    if (this.amount !== null && this.amount !== undefined)
      output = ("" + this.amount)
        .replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1 ");
    return output;
  }
  set rendition(input: string) {
    const negative = input.match(/^[-]/);
    const digits = input.replace(/\D/g, "");
    let output = null;
    if (digits)
      output = +digits * (negative ? -1 : 1);
    this.amount = output;
  }
}

绑定是这样完成的.

<input #amount type="text"
       (keyup)="onKeyUp($event)"
       [(ngModel)]="config.rendition">

我已尝试使用 markForCheck() detectChanges() onKeyUp 中执行检测更改,声明为

I've tried to execute detection change in onKeyUp using markForCheck() and detectChanges() as declared in docs. No difference there.

如何强制输入框实际清除当前内容并将其替换为bound属性的实际值?

How can I force the input box to actual clear up the current content and replace it with the actual value from the bound property?

(可在 Blitzy 上播放的演示.)

(Playable demo on Blitzy.)

推荐答案

即使最终值与现有值相同,也要强制更新视图的技巧是在设置raw( (可能是无效的)值,然后设置正确的值.

The trick to force the view to update even when the final value is the same as the existing one, is to first call ChangeDetectorRef.detectChanges() after setting the raw (and possibly invalid) value, and then to set the correct value.

例如,如果您有一个仅接受数字的文本字段,并且如果处理是在组件代码中完成的,则可以按以下方式实现设置器:

For example, if you had a text field that accepts only digits, and if the processing was done in the component code, you could implement the setter as follows:

private _numericString: string;

get numericString() {
  return this._numericString;
}
set numericString(value) {
  this._numericString = value;     // <------------------------ Set the raw value
  this.changeDetectorRef.detectChanges();   // <--------------- Trigger change detection
  this._numericString = value.replace(/[^\d]/gi, ""); // <----- Set the corrected value
}

请参见在您的实际代码中,config.Rendition被定义为单独类中的getter/setter属性,并且格式化同时在getset中完成,这使得使用原始强制检测更改更加困难价值.解决该困难的一种方法是在组件中定义configRendition getter/setter属性并将该属性分配给ngModel:

In your actual code, config.Rendition is defined as a getter/setter property in a separate class, and the formatting is done in both get and set, making it more difficult to force change detection with the raw value. One way to circumvent that difficulty is to define a configRendition getter/setter property in the component and to assign that property to ngModel:

<input #amount type="text" placeholder="xxx" [(ngModel)]="configRendition">

然后我们可以以这样的方式实现configRendition:在实际设置config.Rendition之前,先使用原始值调用ChangeDetectorRef.detectChanges():

We can then implement configRendition in such a way that ChangeDetectorRef.detectChanges() is called first with the raw value, before actually setting config.Rendition:

private rawRendition: string;

get configRendition() {
  if (this.rawRendition) {
    return this.rawRendition;
  } else {
    return this.config ? this.config.rendition : null;
  }
}
set configRendition(value) {
  this.rawRendition = value;
  this.detector.detectChanges();
  if (this.config) {
    this.config.rendition = value;
  }
  this.rawRendition = null;
}

请参见 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆