Force change detection in pipe (pure or impure) bound to ngModel

Related searches

I'm binding an ngModel value to the angular percent pipe, updating on ngModelChange with updateOn set to blur. It works well except when entering the same value again. When entering the same value again, the pipe does not detect the change and the value shows as a decimal instead of a percent. I have tried recreating the percent pipe as an impure pipe but this did not work. How can I force the pipe to detect the change even if the value is identical to previous value?

Tried having pipe return WrappedValue.wrap(this._latestValue);

Tried running this._ref.detectChanges() in change function

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

Expecting value to be displayed formatted as a percent. Shows decimal value after reentering.

My Stackblitz Code

while trying to find a proper solution, i managed to force pure currency pipe to re-execute with same value (here is the demo). but that didn't solve the problem because even if the pipe re-executes, it eventually returns same result. since that result is binded to ngModel as @Input like [ngModel]="account.percentage | percent: '1.0-2'" ngOnChanges hook in ngModel implementation doesn't update input elements view value.

this is (taken from sources) how ngModel captures changes and updates value/view.

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

and this is the implementation of 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);
}

since there is no change in model within changes: SimpleChanges isPropertyUpdated returns false and view is not updated.

so i tried following hacky workaround to re-initialize the input from scratch and it worked :)

i placed a dummy variable on input to show/hide the element;

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

and whenever ngModelChange emits input is hidden and shown immediately

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

Optimize Angular's change detection, I'm binding an ngModel value to the angular percent pipe, updating on ngModelChange with updateOn set to blur. It works well except when entering … Force change detection in pipe (pure or impure) bound to ngModel. Help Request. Close. 2. Archived. Force change detection in pipe (pure or impure) bound to ngModel.

It will only update once you blur the input since you set the ngModelOptions to only update on blur :)

Removing it should do the trick.

Force change detection in pipe (pure or impure) bound to ngModel, Learn how to optimize your Angular app's change detection to make it more responsive. It also includes an ngModel directive for two-way data binding Both pure and impure pipes accept inputs and return results that can� Earlier in this page, you learned that such pipes must be impure and that Angular calls impure pipes in almost every change-detection cycle. Filtering and especially sorting are expensive operations. The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second.

Try [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" />

Add percent to ngModel value Angular 6 (pipe), I'm binding an ngModel value to the angular percent pipe, updating on ngModelChange with updateOn set to blur. It works well except when� Before doing that, understand the difference between pure and impure, starting with a pure pipe. Pure pipes. Angular executes a pure pipe only when it detects a pure change to the input value. In AngularDart, a pure change results only from a change in object reference (given that everything is an object in Dart).

Transforming Data Using Pipes, Force change detection in pipe (pure or impure) bound to ngModel , Therefore, I have to split [()] into [] and () , and only use pipe in [] . A Stackoverflow solution:� Otherwise only one of the pipes will be updated. However the second difference between pure and impure is that transform will be called on every digest cycle, we don't want this. We already know when to trigger change detection. I'm looking into creating a pure pipe that has multiple instances. For now I'll close this merge request.

Angular looks for changes to data-bound values in a change detection process that runs after every DOM Make a pipe impure by setting its pure flag to false :. Teams. Q&A for Work. Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information.

Pure pipe and impure pipe both detect changes immediately for component string property value changes. So whenever there will be change in value of component property dividend and divisor , our custom pipe division will run every time.

Comments
  • I don't understand why wouldn't it work... what does it matter if the pipe is pure? Same input same output right? Did the pipe just stopped working?
  • hey mah koreh gever? if its pure it only runs the pipe on input change, if its impure it runs every change detection cycle.
  • I've been hitting this issue for a few days now. Something is very fishy. My case is exactly like this, except I use (blur) and have a conditional pipe: <input matInput name="hedgeAmount" placeholder="Hedge amount" [ngModel]="position.hedgeType === 0 ? (position.hedgeAmount / 100 | percent : '1.0-2') : (position.hedgeAmount | currency : position.CurrencyIsoCode : 'symbol-narrow')" (blur)="onBlurHedgeAmount($event)"/> Did you figure out how to make this work?
  • @verynear set the accepted answer to ysf's when you have a moment and if the solution works for you.
  • This looks very promising! Might not be the purest way to make it work, but if it works, it works! :D Will try this afternoon!
  • Yup! Worked! I sent the version into QA this PM, will see if anything comes up but initial tests were fine. Smart workaround, gets exactly the behavior I wanted!
  • without the updateOn: blur it attempts to add the percent sign while the user is still typing. but yes i tried that just to see, and the issue remains even with default (updateOn change)
  • It's hard to debug like this, can you provide something like a gist of the code? Or a stackblitz.com example?
  • stackblitz
  • see above stackblitz link. it works fine until you try to enter the same value twice in a row
  • As mentioned on the other answer, the behaviour for on change is really not usable, as soon as the user types a number, the % gets added. so typing 41 for example ends-up being a strange value like 4.00%1, which does not work. Also, copy-pasting in 64, triggers the reported problem of the pipe not being applied. (maybe a not-dirty detection or something like that?)