Принудительное обнаружение изменений, когда значение, связанное с не изменяется - PullRequest
3 голосов
/ 05 мая 2019

У меня есть компонент, который реагирует на изменение в элементе управления вводом и переформатирует его, удаляя определенные символы. Когда настройка завершена, значение, сохраненное в резервном поле, может измениться или нет. В первом случае все работает, но если удаленный символ отображается на предыдущее значение, изменения не обнаруживаются и компонент не обновляется. Это приводит к тому, что значение, включая удаляемый символ, остается в поле ввода.

Как я могу принудительно связать поле ввода через [(ngModel)] * с полем поддержки, чтобы фактически обновить, изменив введенное значение на значение, обслуживаемое get prop () средство

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">

Я пытался выполнить обнаружение изменений в onKeyUp , используя markForCheck () и detectChanges () , как объявлено в документах . Там нет никакой разницы.

Как заставить поле ввода на самом деле очистить текущее содержимое и заменить его фактическим значением из свойства bound?

(Воспроизводимое демо на Blitzy .)

1 Ответ

2 голосов
/ 06 мая 2019

Хитрость для принудительного обновления представления, даже когда конечное значение совпадает с существующим, состоит в том, чтобы сначала вызвать ChangeDetectorRef.detectChanges() после установки необработанного (и, возможно, недействительного) значения, а затем установить правильное значение.

Например, если у вас было текстовое поле, которое принимает только цифры, и если обработка выполнялась в коде компонента, вы могли бы реализовать установщик следующим образом:

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 в отдельном классе, а форматирование выполняется как в get, так и set, что затрудняет принудительное обнаружение изменений с помощью rawзначение.Один из способов обойти эту трудность - определить свойство configRendition getter / setter в компоненте и присвоить это свойство ngModel:

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

Затем мы можем реализовать configRendition таким способомчто ChangeDetectorRef.detectChanges() вызывается сначала с необработанным значением, прежде чем на самом деле установить 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;
}

См. этот стек для демонстрации.

...