3

The Angular manual for Practical Observables gives an example of using debounce in type-ahead:

const typeahead = fromEvent(searchBox, 'input').pipe(
  map((e: KeyboardEvent) => e.target.value),
  filter(text => text.length > 2),
  debounceTime(10),
  distinctUntilChanged(),
  switchMap(() => ajax('/api/endpoint'))
);

Meanwhile, another part of the manual recommends using Renderer2.listen() for DOM interaction. Also, this Medium post has some pretty emphatic advice to not manipulate the DOM directly.

I've read this related Q&A for 'click' events, which could apply to 'input' events.

What's vexing me is that I'm looking for consistent philosophy of design throughout the Angular manual (and it has plenty of that). This feels inconsistent.

Also, the two approaches are not exactly the same.

In the case of Renderer2.listen() an unlisten() function is returned to prevent memory leaks. Not so with fromEvent. I suspect that fromEvent isn't leaking, but I don't know and more importantly, if it is, why would the manual recommend this method?

Finally, I accept that there may be absolutely no difference between these two methods. Surely, then, the manual would bias towards using Renderer2 in that case.

Which leaves me asking what about the type ahead suggestion is better than the listen() method?


Update

I appreciate the answers and the comment and together, they clarified some things for me. Basically, coding in the event model world saddles the developer with a lot of complexities. It seems that rxjs is in response to that world, an easier/cleaner way to consume events. I also appreciate the Answer that essentially says: "RTFM", so I went and did that, too.

If I decided I had to use Renderer2.listen(), and yet I also want to take advantage of Observables' simpler programming model, I'd have to convert listen() call into an Observable. I believe that looks like this:

new Observable(obs => renderer.listen(el.nativeElement, 'input', e => obs.next(e)))

Which, in the end, I imagine the fromEvent operator does under the covers.

It would seem the advantage of the fromEvent code is also that I don't have to inject a Renderer2 into my component, I need only locate the ElementRef for the target DOM object. The point being, I can have an Observable either way, one of which is much simpler to describe and code.

Andrew Philips
  • 1,950
  • 18
  • 23
  • 1
    RxJS was introduced into Angular 2.0 as an alternative to *promises*. It has become a core design philosophy to use reactive programming, and is consistent with this approach. `listen()` is a replacement for `addEventListener()` which protects source code so it can be used on server-side rendering. `listen()` follows the event programming paradigm and is not consistent with reactive programming. Reactive programming itself is an advanced topic, and it's easier for beginners with Angular to use event programming. It would take 3 times as many lines of code to rewrite the example for events. – Reactgular May 24 '19 at 15:50
  • 1
    Its good that you worry about leaky subscriptions etc ... but its easy to manage. Read this: https://alligator.io/angular/takeuntil-rxjs-unsubscribe/ – Davy May 27 '19 at 17:38
  • @Davy ty for the most excellent suggestion. I already use a *cleanup* Subscription variable that I `add()` subscribes to. `takeUntil` feels better. This is fantastic. – Andrew Philips May 27 '19 at 20:11
  • Yes, its a nice pattern, and works well. People have actually written helpers to make it easier: https://github.com/NetanelBasal/ngx-take-until-destroy But i personally would not introduce a new depency for something this trivial. – Davy May 28 '19 at 13:01

2 Answers2

2

fromEvent is a hot Observable, so potentially it does leak. And it must be unsubscribed as most Observables, for the best practises.

Renderer2.listen() seems to be designed to act if event occurs, while with fromEvent you have more control on the stream itself. You can change its behaviour as in your snippet, with debounceTime, filter etc.

So with fromEvent you control the stream, while with Renderer2.listen() you do some side effects etc.

Julius Dzidzevičius
  • 10,775
  • 11
  • 36
  • 81
1

The sentence right above the code :

Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators:

This means it's just RxJS, no Angular involved. It's just to explain the basics of RxJS.