2

I have a list of components that contain dates(formatted with toLocaleString()) and other things. On top of them there is a component for creating new components, wich contains a form with some inputfields built with angulars FormBuilder. When I type fast the validation lags and the text I'm typing isn't displayed immediately.

I assume that Angular is rerendering all components, because if I don't display the date in the other components I can type pretty fast without lags.

Is there a way to only rerender the input field I'm typing in, since all other components cannot change or is toLocaleString() the problem?

Daskus
  • 929
  • 1
  • 10
  • 25

2 Answers2

6

Is there a way to only rerender the input field I'm typing in, since all other components cannot change

Yes, for the components that will not change, set the change detection strategy for those components to OnPush. An OnPush component will then only be checked for changes if

  • any of its input properties changes
  • it fires an event (e.g., a button click)
  • an observable (which is an input property or a local-to-the-component property) fires an event, and | async is used in the template with the observable (see plunker in the comments below this answer)
import {Component, Input, ChangeDetectionStrategy} from 'angular2/core';

@Component({
  ...
  changeDetection: ChangeDetectionStrategy.OnPush
})

Also consider listening for changes to your input by subscribing to the valueChanges Observable Angular makes available on your form element if you use ngFormControl. You can then use debounce() to only process changes every second or whatever time frame is appropriate:

<input type=text [ngFormControl]="input1Control">
constructor() { 
  this.input1Control = new Control();
}
ngOnInit() {
  this.input1Control.valueChanges
    .debounceTime(1000)
    .subscribe(newValue => console.log(newValue))
}

See https://stackoverflow.com/a/36849347/215945 for a working plunker.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • I haven't found any mention of the "observable fires an event". In [this blog](http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html) they explicitely call `markForCheck` in the `subscribe(...)` callback. Maybe this is only with `| async`? – Günter Zöchbauer Apr 27 '16 at 08:31
  • @GünterZöchbauer see http://victorsavkin.com/post/110170125256/change-detection-in-angular-2 and http://stackoverflow.com/questions/35386822/changedetectionstrategy-onpush-and-observable-subscribe-in-angular-2. In the thoughtram blog you mention, I don't really like the example they give, since they are only changing view state, so `markForCheck()` is overkill... they only need to call `detectChanges()`. I need to play around with this some more (someday)... as I'm not sure what Victor really means when he says "an observable fires an event". If you figure it out, please comment. – Mark Rajcok Apr 27 '16 at 16:01
  • 1
    @GünterZöchbauer, I created a [Plunker](http://plnkr.co/edit/ezpbwhzowWkGQQKgn3FT?p=preview) to test this, and what you said is true: if an input property that is an observable fires an event AND `| async` is used in the template, then the view updates. If `async` isn't used, the view does not update. (Savkin's blog is likely outdated.) But this seems odd to me -- bug? If I imperatively `subscribe()`, I would expect it to work the same way that `async` works (i.e., the declarative/implicit `subscribe()` way). – Mark Rajcok Apr 28 '16 at 04:19
  • I read Victors blog yesterday and was constanrly wondering where and how the "magic" could happen but couldn't find a hint (I assumed because being too tired). Angular can only know about events of observables when it subscribes them (that's what `async` does). I would find it weird if Angular would subscribe and consume an observable (if it's not shared) without me explicitely telling to do so. And as Victor said, they don't require a specific observable implementation there is IMHO no way to patch it like they do with the async API. – Günter Zöchbauer Apr 28 '16 at 04:29
  • 1
    There were a few questions in the comments about this as well and the answers are vague. My impression is they planned to make it work like magic back then and ended with `| async` because there is no proper "magic" available for this use case. Thanks a lot for your feedback about your attempt to reproduce! – Günter Zöchbauer Apr 28 '16 at 04:33
  • 2
    @GünterZöchbauer, thanks for this: "there is no way to patch it like they do with the async API". I assumed it was/could be patched -- i.e, I assumed `subscribe()` was patched. I guess not. And thanks for asking the question (i.e., your original comment)... this was interesting (even if I lost some sleep over it). – Mark Rajcok Apr 28 '16 at 04:42
2

That's a known issue https://github.com/angular/angular/issues/6311

See also

There is also a pull request with a proposed fix, but seems not to be included in the latest beta release.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567