wonderful world
wonderful world

Reputation: 11599

Reactive search with RxJS Observable Vs Subject

The following are two approaches to the same problem, is to do a reactive search for some characters that user enter in a text box. The first solution is from ngrx example and the second one is from an egghead instant search course.

Can someone explain the advantages and disadvantages with these two approaches?

Search using Observable:

@Injectable()
export class BookEffects {

  @Effect()
  search$: Observable<Action> = this.actions$
    .ofType(book.ActionTypes.SEARCH)
    .debounceTime(300)
    .map(toPayload)
    .switchMap(query => {
      if (query === '') {
        return empty();
      }

      const nextSearch$ = this.actions$.ofType(book.ActionTypes.SEARCH).skip(1);

      return this.googleBooks.searchBooks(query)
        .takeUntil(nextSearch$)
        .map(books => new book.SearchCompleteAction(books))
        .catch(() => of(new book.SearchCompleteAction([])));
    });

    constructor(private actions$: Actions, private googleBooks: GoogleBooksService) { }
}

@Component({
  selector: 'bc-find-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <bc-book-search [query]="searchQuery$ | async" [searching]="loading$ | async" (search)="search($event)"></bc-book-search>
    <bc-book-preview-list [books]="books$ | async"></bc-book-preview-list>
  `
})
export class FindBookPageComponent {
  searchQuery$: Observable<string>;
  books$: Observable<Book[]>;
  loading$: Observable<boolean>;

  constructor(private store: Store<fromRoot.State>) {
    this.searchQuery$ = store.select(fromRoot.getSearchQuery).take(1);
    this.books$ = store.select(fromRoot.getSearchResults);
    this.loading$ = store.select(fromRoot.getSearchLoading);
  }

  search(query: string) {
    this.store.dispatch(new book.SearchAction(query));
  }
}

Search using Subject:

import { Component } from '@angular/core';
import { WikipediaSearchService } from './wikipedia-search.service';
import { Subject } from 'rxjs/Subject';

//application wide shared Rx operators
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  items:Array<string>;
  term$ = new Subject<string>();
  constructor(private service:WikipediaSearchService) {

    this.term$
        .debounceTime(400)
        .distinctUntilChanged()
        .switchMap(term => this.service.search(term))
        .subscribe(results => this.items = results);
  }
}

<div>
  <h2>Wikipedia Search</h2>
  <input (input)="term$.next($event.target.value)">
  <ul>
    <li *ngFor="let item of items">{{item}}</li>
  </ul>
</div>

Upvotes: 1

Views: 1587

Answers (1)

Babar Hussain
Babar Hussain

Reputation: 2905

Behavior Subject is a type of subject, a subject is a special type of observable so you can subscribe to messages like any other observable. The unique features of a behavior subject are:

  • Behavior subject needs a initial value as it must always return a value on subscription even if it hasn't received a next()
  • Upon subscription it returns the last value of the subject. A regular observable only triggers when it receives a onnext at any point you can retrieve the last value of the subject in a non-observable code using the getValue() method.
  • Unique features of a subject compared to a observable are:

It is a observer in addition to being a observable so you can also send values to a subject in addition to subscribing to it. In addition you can get a observable from behavior subject using the asobservable() method on behaviour subject.

Observable is a Generic, and Behavior subject is technically a sub-type of Observable because behavior subject is a observable with specific qualities.

An observable can be created from both Regular and Behavior Subjects using subject.asobservable(). Only difference being you can't send values to a observable using next() method.

In angular2 services, I would use behavior subject for a data service as a angular service often initializes before component and behavior subject ensures that the component consuming the service receives the last updated data even if there are no new updates since the component's subscription to this data. In short many things are similar in observable/subject/BehaviorSubject etc it depends on your need.

Upvotes: 2

Related Questions