Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 with NGRX getting "You provided 'undefined' where a stream was expected.upon dispatch"

I'm trying to fetch some recipes over an API using ngrx and an interceptor that checks the URL to determine what kind of auth tokens that should be used. But for some reason that I have not manage to figure out I get and the following error:

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:41)
    at subscribeToResult (subscribeToResult.js:6)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._innerSub (mergeMap.js:70)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (mergeMap.js:67)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (mergeMap.js:50)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at Observable._subscribe (scalar.js:5)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:28)
    at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (mergeMap.js:28)

Below is where I try to dispatch the action when my component is initiated:

constructor(private router: Router,
                  private route: ActivatedRoute,
                  private store: Store<fromRecipe.FeatureState>) { }

  ngOnInit() {
    this.recipeState = this.store.select('recipes');
    this.store.dispatch(new RecipeActions.FetchRecipesFromApi());
  }

This is the effect action that gets called:

@Effect()
    recipesFetchFromAPI = this.actions$
        .ofType(RecipeActions.FETCH_RECIPES_FROM_API)
        .pipe(switchMap((action: RecipeActions.FetchRecipesFromApi) => {
            return this.httpClient.get<ApiSearch>('https://api.edamam.com/search')
            }),
            map(
                (searchResult) => {
                    return {
                        type: RecipeActions.SET_RECIPES,
                        payload: searchResult.hits
                    }
                }
            )
        );

This is my interceptor that checks what url the request is from.

intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        if(req.url == 'https://ng-recipe-book-55fbc.firebaseio.com/recipes.json'){
            return this.store.select('auth')
                .pipe(
                    take(1),
                    switchMap((authState: fromAuth.State) => {
                        const clonedReq = req.clone({params: req.params.set('auth', authState.token)});
                        return next.handle(clonedReq);
                    })
                );
        } else if (req.url == 'https://api.edamam.com/search?q=chicken') {
            const clonedReq = req.clone({params: req.params.set('app_id', '123').set('app_key', '123')});
            return next.handle(clonedReq);
        }
    }

My other actions, reducers and effects are working but this one. I have browsed the forum but have not managed to find a solution for this perticular problem. Does anyone have an idea of what is causing this? I would happily provide more code/information if that's needed.

like image 976
emmep Avatar asked Sep 12 '25 03:09

emmep


1 Answers

My guess (you haven't pinpointed the problem area) is that the HTTP response is not 2xx. You are not handling error responses and so your effect will disable itself and never fire again. Here's how you should be handling errors:

@Effect()
  allFiltersRequested$ = this.actions$.pipe(
    ofType<AllFiltersRequestedAction>(FiltersActionTypes.AllFiltersRequested),
    mergeMap(() =>
      // essential to catchError else an HTTP error response will disable this effect
      this.simService.getAllFilters().pipe(
        catchError(() => {
          return of({})
        })
      )
    ),
    map((allFilters) => new AllFiltersLoadedAction(allFilters))
  )

Whatever you return in the return of statement will be passed to map on failure. The effect also will not disable itself. This is the approach that Udemy promotes.

like image 108
danday74 Avatar answered Sep 13 '25 18:09

danday74