All Articles

Observable for Angular Output

I have one suggestion for you guys for using Observable for Output in Angular. I thought you might not know about that because it wasn’t get mentioned in the documentation. Take a look at the below code and and I will explain on the later part.

Before

@Output() someEvent = new EventEmitter();
this.someSource$.pipe(
   /* additional logic transformation */
).subscribe(data => this.someEvent.emit(data));

After

@Output() someEvent = this.someSource$.pipe(
  /* additional logic transformation */
);

As you can see, the before and after code was pretty much identical. Its use-case is applicable when you want to use Output to emit something for the Parent Component when someSource$ emit data. But why it works?

To go a bit deeper, you need to understand two things:

  • Event Binding syntax (eventName)
  • class EventEmitter

Event Binding Syntax ()

Event binding is what you see when using a parenthesis and a event name on the template part, e.g. <child (someEvent)="invokeSomeEvent()"></child>.

Basically, Angular Compiler will parse all the template to Abstract Syntax Tree (AST) so that I can have all information regarding the current template. For the event binding, Angular knows which event get binding on the template itself.

If you look at source code of output_interpreter, there is one path to check if the current event is SubscribeObservable, it will automatically subscribe to that Observable.

Observable for Angular Output

What does this mean? If event is either Observable/Subject, Event Binding syntax () will automatically do the subscribe.

EventEmitter class

EventEmitter is a subclass of Subject under the hood. And as you might have already known, Subject acts as both Observable and Observer. With the code on the above output_interpreter, if you change an EvenEmitter with a Subject/Observable, it will be automatically subscribed.

When you understand the two concepts Event Binding syntax and EventEmitter, I hope you get why the above code works.

Some use-case

  • Interval Output
  • State Selector (ngrx)
  • … Anything related to streams…

Example

Angular team also use this approach for one of their search-box component example. Thanks chandlerfang for the input!

View the source code

@Component({
  selector: 'aio-search-box',
  template: `
    <input
      #searchBox
      type="search"
      aria-label="search"
      placeholder="Search"
      (keyup)="doSearch()"
    />
  `,
})
export class SearchBoxComponent implements AfterViewInit {
  private searchDebounce = 300
  private searchSubject = new Subject<string>()

  @Output() onSearch = this.searchSubject.pipe(
    distinctUntilChanged(),
    debounceTime(this.searchDebounce)
  )

  doSearch() {
    this.searchSubject.next(this.query)
  }
}

Have fun!

Thanks Chau Tran for the original Vietnamese version.

Published 9 Jan 2021

Recent Posts

Build an Angular component to display snow ❄️ effect

The holiday session is coming. Let add a simple snow effect to your Angular application ❄️❄️❄️

10 Modern CSS layout and sizing techniques

Learn a few layout tricks you can implement in your codebase today, and be able to write entire swaths of layout with just a few lines of code.


Follow @tuantrungvo on Twitter for more!