Difference between concat and merge in rxjs6

Viewed 439

I have lessons$ observable which is combined from initialLessons$ and searchLessons$ observables.

initialLessons$ emits on the load of the page to get a list of lessons and when the user types in the search input searchLessons$ emit to get the filtered results.

When I used concat to combine these observables, only the initialLessons$ observable emits and it seems that it doesn't subscribe to searchLessons$ at all. I replaced it with merge and it worked fine

I just need to know what's the explanation for this case!

export class CourseComponent implements OnInit, AfterViewInit {
  @ViewChild('searchInput') input: ElementRef;

  courseId: string = this.route.snapshot.params['id'];

  course$: Observable<Course>;

  lessons$: Observable<Lesson[]>;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.course$ = createHttpObservable(`/api/courses/${this.courseId}`);
  }

  ngAfterViewInit() {
    const initialLessons$: Observable<Lesson[]> = this.loadLessons();

    const searchLessons$: Observable<Lesson[]> = fromEvent<any>(
      this.input.nativeElement,
      'keyup'
    ).pipe(
      debounceTime(400),
      map(event => event.target.value),
      distinctUntilChanged(),
      switchMap(search => this.loadLessons(search))
    );

    this.lessons$ = merge(initialLessons$, searchLessons$);
  }

  loadLessons(search = ''): Observable<Lesson[]> {
    return createHttpObservable(`/api/lessons?courseId=${this.courseId}&pageSize=100&filter=${search}`
).pipe(map(res => res['payload']));

} }

Edit:

This is createHttpObservable code:

import { Observable } from 'rxjs';

export const createHttpObservable = (url: string) => {
  return Observable.create(observer => {
    const controller = new AbortController();
    const signal = controller.signal;

    fetch(url, { signal })
      .then(res => res.json())
      .then(data => observer.next(data))
      .catch(err => console.error(err));

    return () => controller.abort();
  });
};
1 Answers

concat will subscribe only to the next source Observable when the previous Observable completes.

And this is what doesn't happen in your code. An Observable created by createHttpObservable never completes. It only emits one next() but no complete(). So that's why you were experiencing what you described. concat never subscribed to searchLessons$ because initialLessons$ never completed.

Since you're already calling .then(data => observer.next(data)) you can add there also complete() call.

.then(data => {
  observer.next(data);
  observer.complete();
})
Related