4

I am working on Angular 6 with Rxjs 6 while I have a question regarding returning a null/empty Observable if response failed or has exception, Here is my assumption, my remote api will return an object of IOptionResponse, it contains a message string which could be indicated like 'SUCCESS' or 'FAILED', it also contains a model which is an array of 'IOption' object

export interface IOptionResponse {
    message: string;
    model: IOption[];
}

Here is my service method name, it will return a Observable of IOption array which is the "model" of my remote API result

loadIOptionMembersRelationship(): Observable<IOption[]> {
    return this.httpClient.get<IOptionResponse>('${environment.apiUrl}/api/member/XXX')
        .map(
            (response) => {
                console.log(response);
                // if response.message is success, return IOption[] model
                if (response.message == responseMessage.Success) {
                    return response.model;
                }
                else {
                    // return Observable.empty<IOption[]>(); failed
                    // return new Observable.empty<IOption[]>(); failed
                    // return new EmptyObservable<IOption[]>(); failed
                    // return new Observable<IOption[]>.from([]); failed
                    // Otherwise return a NULL/EMPTY Observable
                    //What should be the correct way to implement here???
                }
            }
        );
}

I've read the post here which is similar, however I tried all the possible solution and they do not work, I am not sure if it's because that posted solutions are out of date or maybe some method changed in rxjs 6 or maybe it's a typescript issue...

CozyAzure
  • 8,280
  • 7
  • 34
  • 52
Drex
  • 3,346
  • 9
  • 33
  • 58
  • It depends how you want to react on such a "Failure". You could throw an Error, that would allow you (and all subscribers of your Method) to handle it with normal catchError(...). An empty Observable or one with "undefined" as content will go through the whole stream, every map, every tap, everything. All those places than have to know how to handle this "empty" Observable. If it´s an error, make it sound and throw an Error, that you can catch later in the eventstream – JanRecker Jul 20 '18 at 07:23
  • The return of map should not be an observable, so just `return null` will complete the observable with a null value. If you want to terminate the observable empty in the case of an error, you should be using flatMap or switchMap or similar, where it would be simply `empty()` to terminate the observable without returning anything, or `of(null)` to return a null value. – Mark Hughes Jul 20 '18 at 09:08

5 Answers5

11

If you want to return an empty Observable array while using Rxjs6, you need to...

import { of } from 'rxjs';

Then where you want to return your empty Observable array of <IOption[]> type ...

return of<IOption[]>([]);
  • This is the exact solution for my Observable.of([]) Variant in Angular2 and this works now with Angular 7. Sometime, you just want to give an empty arrays back if you can not fetch anything. – Yingding Wang May 07 '19 at 12:34
1

Do you care about FAILED results? If you do not (which is quite true since you want to emit an empty Obersavble), you can just simply filter it. Then you do not need to explicitly emit an empty Observable:

 loadIOptionMembersRelationship(): Observable<IOption[]> {
    return this.httpClient.get<IOptionResponse>('${environment.apiUrl}/api/member/XXX')
        .filter(response => response.message === responseMessage.Success) //only emit those response whose message is SUCCESS
        .map(response => response.model);
}

Explicitly returning an empty Observable will terminate the stream, which may or may not be what you want depending on your implementation.

CozyAzure
  • 8,280
  • 7
  • 34
  • 52
1

All solution from the post you mention will not trigger "next" callback and your workflow will not work. Just simply do

return;

But in this case you will loose error information. I think best way to do it is following

throw new Error("Failed to get the model...");
Mihail
  • 403
  • 4
  • 8
1
public yourMethod() {
    return new Observable<SomeType[]>((observer) => {
      return observer.next(null); //when you want to return NULL/Empty.
      observer.next(ActualReturnValue); //When you want to return actual value.
    });
  }

calling the method

this.yourMethod().subscribe(response=> {
  if(response)
        //CODE
  else
        //CODE
        
},error => {
    console.log(error);        
});
maniac
  • 159
  • 2
  • 10
0

When using map() you transform the data the new observable emits based on its source observable. The problem you have is that you try return an empty Observable although your Observable should return a value of type IOptionsResponse. So your Observable is based of your code an Observable<IOptionsResponse | Observable<IOptionsResponse>>. You could just return null or undefined in your else.

SirDieter
  • 309
  • 2
  • 9