Обнаружение изменения силы в канале (чистом или нечистом), привязанном к 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


person verynear    schedule 03.05.2019    source источник
comment
Не понимаю, почему не работает ... какое это имеет значение, если труба чистая? Тот же ввод, тот же вывод, верно? Труба просто перестала работать?   -  person Shachar Har-Shuv    schedule 03.05.2019
comment
эй мах корей гевер? если он чистый, он запускает конвейер только при изменении ввода, если он нечистый, он запускает каждый цикл обнаружения изменений.   -  person verynear    schedule 03.05.2019
comment
Я сталкиваюсь с этой проблемой уже несколько дней. Что-то очень подозрительное. Мой случай точно такой же, за исключением того, что я использую (размытие) и использую условный канал: ‹input matInput name = hedgeAmount placeholder = Hedge amount [ngModel] = position.hedgeType === 0? (position.hedgeAmount / 100 | percent: '1.0-2'): (position.hedgeAmount | currency: position.CurrencyIsoCode: 'symbol-thin') (blur) = onBlurHedgeAmount ($ event) / ›Вы придумали, как заставить это работать?   -  person Sébastien Richer    schedule 10.07.2019
comment
@verynear устанавливает принятый ответ на ysf, когда у вас есть время, и если решение работает для вас.   -  person Sébastien Richer    schedule 16.07.2019


Ответы (3)


пытаясь найти правильное решение, мне удалось заставить чистый канал currency повторно выполнить с тем же значением (вот демонстрация). но это не решило проблему, потому что даже если конвейер повторно запускается, он в конечном итоге возвращает тот же результат. так как этот результат привязан к ngModel как @Input как [ngModel]="account.percentage | percent: '1.0-2'" ngOnChanges в хуке реализация ngModel не обновляет значение представления элементов ввода.

это (взято из источников a>) как 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);
}

поскольку нет изменений в model в пределах changes: SimpleChanges isPropertyUpdated возвращает false и представление не обновляется.

поэтому я попытался выполнить обходной путь, чтобы повторно инициализировать ввод с нуля, и это сработало :)

я поместил фиктивную переменную на ввод, чтобы показать / скрыть элемент;

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

== >>> вот рабочая демонстрация ‹*** = знак равно

person ysf    schedule 10.07.2019
comment
Это выглядит очень многообещающе! Возможно, это не лучший способ заставить его работать, но если он работает, он работает! : D Постараюсь сегодня днем! - person Sébastien Richer; 11.07.2019
comment
Ага! Работал! Я отправил версию в QA в этот PM, посмотрю, появится ли что-нибудь, но первоначальные тесты прошли нормально. Умный обходной путь, работает именно так, как я хотел! - person Sébastien Richer; 12.07.2019

Он будет обновляться только после размытия ввода, поскольку вы устанавливаете ngModelOptions на обновление только при размытии :)

Его удаление должно помочь.

person Kapulara    schedule 03.05.2019
comment
без updateOn: blur он пытается добавить знак процента, пока пользователь все еще набирает текст. но да, я попробовал это просто чтобы увидеть, и проблема остается даже по умолчанию (updateOn change) - person verynear; 03.05.2019
comment
Так сложно отлаживать, можете ли вы дать что-то вроде сути кода? Или пример stackblitz.com? - person Kapulara; 03.05.2019
comment
stackblitz - person verynear; 03.05.2019
comment
см. ссылку на stackblitz выше. он работает нормально, пока вы не попытаетесь ввести одно и то же значение дважды подряд - person verynear; 03.05.2019

Попробуйте [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" />
person Mahi    schedule 10.07.2019
comment
Как упоминалось в другом ответе, поведение при изменении действительно не используется, как только пользователь вводит число, добавляется%. поэтому ввод 41, например, приводит к странному значению, например 4.00% 1, что не работает. Кроме того, копирование в 64 вызывает проблему, о которой сообщается, что канал не применяется. (может быть, не-грязное обнаружение или что-то в этом роде?) - person Sébastien Richer; 10.07.2019