6

I am using an Angular service to allow the user to upload files.

The implementation of the service is working ; my question is about RxJS and its pipeable operators, but here is the service signature just in case :

askUserForFile(): Observable<File>;
toBase64(file: File): Observable<string>;
isFileValid(file: File, configuration?: { size?: number, extensions?: string | string[] }): boolean;

The call to this service is as follows :

  this.fileService
    .askUserForFile()
    .pipe(
      // this is the operator I'm looking for 
      unknownOperator(file => this.fileService.isFileValid(file, { extensions: ['txt'] }))
      mergeMap(file => {
        fichier.filename = file.name;
        return this.fileService.toBase64(file);
      }))
    .subscribe(base64 => {
      fichier.base64 = base64;
      // Rest of my code
    }, error => {/* error handling */});

I would like to find an operator in place of unknownOperator that would throw an error if the condition isn't met.

I've tried with

  • filter : if the condition isn't met, the code stops after it,
  • map : the code continues even if an error is thrown with throwError

I thought about using the following piping

.pipe(
  map(...),
  catchError(...),
  mergeMap(...)
)

Which I think might work, but I would like to find (if possible) an operator that shortens this piping.

Is it possible ? if not, is there a better piping ?

2
  • 2
    I'd just call isValidFile within the mergeMap and, if it returns a false value, either return a throwError observable or just throw an error. Commented Aug 21, 2018 at 13:00
  • @cartant it works too, thank you, but I would have liked to be able to use an operator for that, I think this would have been cleaner Commented Aug 21, 2018 at 13:02

1 Answer 1

4

You can use just map but you have to throw an exception with throw keyword, not returning throwError because this just creates another Observable. You could also use mergeMap and then throwError would work but it's probably unnecessarily complicated.

map(val => {
  if (val === 42) {
    throw new Error(`It's broken`);
  }
  return val;
})

oneliner:

mergeMap(val => val === 42 ? throwError(new Error(`It's broken`)) : of(val))
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, it works, but it removes the one-line condition ; is this the only way of doing it ?
Then it's probably easier to use mergeMap, see my update
It works too, but renders nasty because of the linter : mergeMap(file => (this.fileService.isFileValid(file, { extensions: ['txt'] }) ? of(file) : throwError('Error ...')) as Observable<File>) ... So there's really no built-in operator for that except for workarounds like that ?
well, you can put this into a custom operator.
I've never went that far into RxJS, I didn't know you could do that ! Thank you for the heads-up, I think I'm going to do that