"rxjs" observable.throw is not a function - Angular4
Asked Answered
L

5

45

I've been learning Angular 4 and everything was going smoothly until I tried to implement catch handling in a service. I'm trying to use "rxjs" catch and throw but I've got an undefined function error in my console.

import { Injectable } from '@angular/core';
import { Http } from "@angular/http";
import { Observable } from 'rxjs/observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { AppError } from "../app/common/app.error";
import { NotFoundError } from "../app/common/not-found-error";
import { BadInput } from "../app/common/bad-input";

@Injectable()
export class PostService {
  private url = "https://jsonplaceholder.typicode.com/posts";

  constructor(private http: Http) { }

 deletepost(post){
      // return this.http.delete(this.url + '/' + post.id)
      // Hard-coded id to test 404
      return this.http.delete(this.url + '/' + 93498)
        .catch((error: Response) => {
          console.log('error within catch is ' + Response)
          if(error.status === 404)
            return Observable.throw(new NotFoundError(error));

          return Observable.throw(new AppError(error));
        });
    }
}

This is the error message:

TypeError: __WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw is not a function. 
(In '__WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw(new 
__WEBPACK_IMPORTED_MODULE_6__app_common_not_found_error__["a" /* NotFoundError 
*/](error))', 
'__WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw' is 
undefined) — post.service.ts:42

I also have this warning in my browser:

./~/rxjs/Observable.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/rxjs/Observable.js
    Used by 14 module(s), i. e.
    /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/@angular/core/@angular/core.es5.js
* /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/rxjs/observable.js
    Used by 1 module(s), i. e.
    /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/@ngtools/webpack/src/index.js!/Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/src/services/post.service.ts
Lyly answered 2/8, 2017 at 15:20 Comment(4)
Try importing import { Observable } from 'rxjs/Observable'; with a capital "O" instead of import { Observable } from 'rxjs/observable'; with a lowercase "o" and see if that makes any difference.Donnenfeld
@AlexanderStaroselsky Wow I can't believe that was the reason why. I didn't notice that it was higher case O because it doesn't match the naming convention of all the other imported dependencies. You should post this as the answer so I can mark it as correct.Lyly
I've experienced the same thing, the error doesn't always make it clear. Mind if I put that as an answer so that other experiencing the issue may find a solution?Donnenfeld
@AlexanderStaroselsky Yeah go for it. Create an answer for this question and i'll mark it as correct. Thanks for your help.Lyly
D
128

The error There are multiple modules with names that only differ in casing. is indicating the wrong import is being targeted with how you are trying to use Observable.

The import should be with a capital "O" like:

import { Observable } from 'rxjs/Observable';

This will import the individual Observable operator, which be used in combination with operators such as catch or throw on created Observables.

import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

To import the full Observable object you'd import it like this:

import { Observable } from 'rxjs/Rx'

Update:

With newer versions of RxJS (5.5+) operators such as map() and filter() can used as pipeable operators in combination with pipe() rather than chaining. They are imported such as:

import { filter, map, catchError } from 'rxjs/operators';

Keep in mind terms such as throw are reserved/key words in JavaScript so the RxJS throw operator is imported as:

import { _throw } from 'rxjs/observable/throw';

Update:

For newer versions of RxJS (6+), use this:

import { throwError } from 'rxjs';

and throw an error like this:

if (error.status === 404)
    return throwError( new NotFoundError(error) )
Donnenfeld answered 2/8, 2017 at 17:51 Comment(9)
Importing the full Observable - import { Observable } from 'rxjs/Rx' - increases bundle size. From the docs: github.com/ReactiveX/rxjs To import only what you need by patching (this is useful for size-sensitive bundling): import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/map';Gutshall
Yes, import { Observable } from 'rxjs/Rx'; can significantly add to the bundle size as it's importing the full Observable object. In most cases I'd argue it's just not needed, but I wanted to provide it as an option as each application is different and may need that kind of control.Donnenfeld
@AlexanderStaroselsky bless you man helped me a lot, whats the difference beween import {Observable} from "rxjs/Observable and import {Observable} from "rxjs because i had problem with Observable throw(error) it only worked when i removed /Observable at the endJaffna
@Jaffna Without the /Observable it sounds like you are likely importing the full Observable object that includes methods such as throw. Depending on your RxJS version, I'd recommend to avoid importing the full Observable object and instead utilize Pipeable Operators. Angular has documentation demonstrating using RxJS including using catchError to handle errors. Importing the full Observable object brings in stuff you simply may not need.Donnenfeld
//import {Observable} from "rxjs/Observable"; import { Observable } from 'rxjs'; this are the two first doesnt work well with private handleError (error: HttpResponse<Truck> | any) { console.error(error.ok || error); return Observable.throw(error.status); }Jaffna
was not able to observe the status code @AlexanderStaroselsky with first one , but i want to know how to use the first one handle error it simply did not work when i changed i was able to observe my errorsJaffna
Observable.throw() is NOT available for import { Observable } from 'rxjs/Observable'; Methods like throw() are available on Observable when importing the full Observable object either through import { Observable } from 'rxjs/Rx'; or simply import { Observable } from 'rxjs';. However you can import { Observable } from 'rxjs/Observable'; then import 'rxjs/add/observable/throw'; and it should work. Check this StackBlitz. I'd also recommend to create a new question to help resolve any specific issues you are having.Donnenfeld
I had to import both import { Observable } from 'rxjs/Observable'; and import 'rxjs/add/observable/throw'; to avoid the error message rxjs observable.throw is not a function.Premed
Thank you for sharing detailed information. In my case only import 'rxjs/add/observable/throw'; didn't work. After that I tried both import line import 'rxjs/add/observable/throw'; import { _throw } from 'rxjs/observable/throw'; and it works like a charmStralka
M
30

In RxJS 6, Observable.throw() is replaced by throwError() which operates very similarly to its predecessor. So, you can replace from Observable.throw(error) to only throwError(error) by importing:

import { throwError } from 'rxjs';

Checkout this link for further reference: https://www.metaltoad.com/blog/angular-6-upgrading-api-calls-rxjs-6

Mattland answered 1/11, 2018 at 19:13 Comment(1)
This saved me! This is the new fixWally
E
13

I was facing the same issue in my angular 5 application. What I did is, adding a new package.

import { throwError } from 'rxjs';
import { filter, map, catchError } from 'rxjs/operators';

And from my http service call I return a function.

return this.http.request(request)
      .pipe(map((res: Response) => res.json()),
        catchError((res: Response) => this.onError(res)));

And in onError function I am returning the error with throwError(error).

onError(res: Response) {
    const statusCode = res.status;
    const body = res.json();
    const error = {
      statusCode: statusCode,
      error: body.error
    };
    return throwError(error);
  }
Egin answered 11/7, 2018 at 10:1 Comment(2)
This solution worked in my Angular 6 app w/ rxjs 6.0. My import statement is already import { Observable } from 'rxjs/Observable' , while doing this I still get the Observable.throw is not a function error. I tried import 'rxjs/add/observable/throw' but it gave a compiler error.Doityourself
Thanks Sibeesh !!Basel
H
4

_throw has been discarded in newer versions of RxJS
For newer versions of RxJS (6+), use this:

 import { throwError } from 'rxjs'; 

and throw an error like this:

 if (error.status === 404)
    return throwError( new NotFoundError(error) )
Hopple answered 6/12, 2019 at 13:2 Comment(1)
This worked for me. throwError inherits from Observable so it was a straight swap.Replacement
D
0

In Angular9 Observable:

  1. if data arrived and status is OK, then send the data
  2. If STATUS of the data is NOT OK, then throw an error
myObsFunc(): Observable<any> { 
  return this.http.get<any>('/api/something') 
    .pipe(
      /* Catch a backend error and let the component know */
      catchError( err => {
        /* Rethrow error */
        return throwError( err );
      }),
      map( (res)=> {
        if( res.STATUS == "OK" ) {
          /* Send DATA to subscriber */
          return Object.values( res.DATA)
        } else {
           /* Inform subscriber that a functional error occured */
           throw ( "getOrphans: Status is not OK but "+ res.STATUS ) ;
        }   
      }),
    )   
}
Drisko answered 3/5, 2020 at 22:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.