Return an empty Observable
Since all the answers are outdated, I will post the up to date answer here
In RXJS >= 6
import { EMPTY } from 'rxjs'
return EMPTY;
how to return an empty observable
Observable.of()
should work for your case:
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
// or import {Observable} from 'rxjs/Rx';
return Observable.of();
or
import {EmptyObservable} from 'rxjs/EmptyObservable';
return new EmptyObservable();
Handle http error using switchMap and return empty Observable
First option is to complete an observable sequence, i.e.
.pipe(
switchMap(_ => this.httpClient.get<IUserInfo>(`/users/{id}`))
catchError(userInfo => {
// Do something with error, like log, etc
return empty()
})
)
in this case, if previous observable (httpClient) throws an error, it will be completed, ie subscription section will not be reached... Ideal case in your case
Second option is to return predictable results, for example if endpoint returns an array, you can return an observable of empty array
.pipe(
switchMap(_ => this.httpClient.get<IUserInfo>(`/users/{id}`))
catchError(userInfo => {
// Do something with error, like log, etc
return of({})
})
)
Third option is to property handle error in subscriber, but it will not be your case as long as you use async pipe
.pipe(
switchMap(_ => this.httpClient.get<IUserInfo>(`/users/{id}`))
)
.subscribe(res => {}, err => {
// return predictable results here
})
Although I'd recommend to achieve this with ErrorHandler Interceptor and additional checks. Error handler interceptor will catch all server error and handle error accordingly.. In your case you also can prepend api origin via interceptor, so you don't have to add it manually to each service
@Injectable({
providedIn: 'root'
})
export class ApiInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Appending environment.origin only if url is not starts with protocol
if (!req.url.match(new RegExp('^https?://'))) {
req = req.clone({
url: environment.origin + req.url
});
}
return next.handle(req).pipe(
catchError(error => {
if (error instanceof HttpErrorResponse) {
// Do something with an error here
}
return throwError(error);
})
);
}
}
.pipe(
switchMap(_ => this.httpClient.get<UserInfo>(`/users/{id}`)),
map(userInfo => !userInfo || typeof userInfo !== 'object' ? {} : userInfo),
catchError(err => empty())
)
Also, get through TypeScript Coding Guidelines . IUserInfo is not complied with it...
How to test if returned Observable is EMPTY
It seems that we have a specific operation in RxJs that checks if an observable is empty. The operation is isEmpty()
it('should return EMPTY when ...', (done) => {
actions$ = of(someAction)
effects.effect$.pipe(isEmpty()).subscribe( (res) => {
expect(res).toEqual(true)
done()
});
res will be true only if observable does return with empty
Subscribe callback not called when empty Observable returned
Observables act differently to promises. The RxJS EMPTY
Observable doesn't call the 'success' callback, only the 'complete' callback. The done
function should be called in 'complete' rather than in 'success':
funcToTest().subscribe({
success() { /* Called when 'x' is returned, e.g. after the subscriber calls 'next' */ },
error(err) { /* Called on an error. */ },
complete() {
/* Called after the subscriber calls 'complete'. No more values can be returned */
done();
}
});
See the examples in the docs: https://rxjs-dev.firebaseapp.com/guide/observable
Return an empty Observable from an Angular2 Service
Replace Observable.empty()
with Observable.of([])
. The perference of of
over empty
is what the official Angular Tour of Heroes tutorial uses to return an empty observable, and is what I have been using in all my apps.
The difference between them seems to be whether nothing is returned, or an empty array.
From the official rxjs docs:
Observable.empty()
Creates an Observable that emits no items to the Observer and immediately emits a complete notification.
Observable.of()
Creates an Observable that emits some values you specify as arguments, immediately one after the other, and then emits a complete notification.
map and filter on observable return empty result
not sure about your observable and when you expect it to emit, but a possiblility is because you are using a Subject
that only will emit when you do a .next
. can you try switching it to a BehaviorSubject
, that will emit whenever something subscribes to it. (although I don't know why adding a .pipe()
would change that)
Why doesn't EMPTY complete the observable?
Try to use the third callback:
this.claimStoreService.setProducts(this.claim.products)
.pipe(switchMap(x => {
if (this.incomeEligibility) {
return this.claimStoreService.saveIncomeEligibility();
} else {
return EMPTY;
}
}))
.subscribe(
() => this.goIntoDisplayMode(),
console.err,
() => this.isSaving = false,
);
RxJS Type signature of EMPTY observable?
I think you can try Observable<never>
, got the idea from EMPTY
's implementation
export const EMPTY = new Observable<never>(subscriber => subscriber.complete());
Related Topics
Show Base64 Pdf Data Using Window.Open on Chrome New Version
How to Style HTML Select Option Hover and Selected Option Effects
To Get a Popup Message After Submit
Fetch() Unexpected End of Input
Print Pdf Directly from JavaScript
Vue.Js Add Objects to Existing Array
Call a Function from an If-Statement Inside a Function
How to Specify Multiple Conditions in an If Statement in JavaScript
Is There Any Memory Limit for Google Chrome Browser
How to Automatic Click a Button on a Webpage
Automatically Force Mobile Browser to Desktop View
Creating a Json Dynamically With Each Input Value Using Jquery
Prevent a White Space in the Beginning of a Input
How Get Total Sum from Input Box Values Using JavaScript
Instead of Downloading, Files Are Opening in Browser
Javascript: Location.Href to Open in New Window/Tab
How to Close Toggle Menu When Clicking Navigation Item Anchor Link