Search code examples
angularrxjs

How to handle "EmptyError: no elements in sequence"?


My issue has nothing to do with the Angular router bug.

I have a component that can be dragged and dropped. The code for the drag and drop functionality looks like this:

@HostListener('mousedown')
onMousedown(): void {
  const mousemove$ = Observable.fromEvent(document, 'mousemove');
  const mouseup$ = Observable.fromEvent(document, 'mouseup');

  const modifiedMouseMove$ = mousemove$
    .map(some transformations)
    .takeUntil(mouseup$);

  modifiedMouseMove$.subscribe(do something on each move);
  modifiedMouseMove$.last().subscribe(drop the item)
}

If I just "click" on the item, I get:

Error: EmptyError { message: 'no elements in sequence', ... }

I'm assuming the issues is that when I click, it fires a mousedown -> mouseup, with no mousemove events in between. Causing the modifiedMouseMove$ to be "empty" and the call to .last() returns nothing. This error does not impact the functionality of my application. I can catch it and do nothing:

modifiedMouseMove$.last().subscribe(() => drop the item, (err) => {
  if (err.name === 'EmptyError') { 
    return;
  } else {
    throw err;
  }
});

Now it doesn't show up in the console anymore, but purposefully swallowing an error seems...bad. How do I actually handle the error?

Should I not activate the second subscription (with the last() operator) if there are no mouse moves? If so, what's the best way to do that?

Is there a magical operator that will only subscribe if there is an event and leave the observable cold otherwise?


Solution

  • If you want just the last item from an Observable and you're fine when there's none it's better to use the takeLast(1) operator:

    modifiedMouseMove$.takeLast(1).subscribe(...)
    

    The last() and first() operators require one and only one matching item. Any other situation results into an error notification.