user5260143
user5260143

Reputation: 1098

rxJS and ngrx - what is the right structure of success / fail inside an effect?

I work in angular 2 Project and use ngrx and rxjs technologies.

Now I have a problem:

I try to declare an Effect. The effect has http request, and only when it success I want to call other http-request, and so only if it also success - then dispatch an success-action.

I has tested it by throw an error but it always dispatch the action!

See:

       @Effect()
createEntity$ = this.actions$.ofType(CREATE_ENTITY)
    .switchMap((action: CreateEntity) => {

        return this.httpService.getDefaultEntityData(action.payload.type).map((entity) => {
            return  Observable.throw("testing only");
            /*if (entity) {
                 entity.title = entity.type;
                 return this.httpService.addEntity(entity);
            }*/
        })

            .catch((error) => Observable.of(new createEntityFailure(error)))
            .map(mappedResponse => ({ type: CREATE_ENTITY_SUCCESS, payload: mappedResponse }))
    });

Upvotes: 0

Views: 768

Answers (3)

Aleksandr Petrovskij
Aleksandr Petrovskij

Reputation: 1243

1) If you returning Observable you probably want swithMap instead of map

2) Action always has been dispatched because you return non error Observable from catch. Changing Observable.of to Observable.throw will throw error further

@Effect()
createEntity$ = this.actions$.ofType(CREATE_ENTITY)
    .switchMap((action: CreateEntity) =>
        this.httpService.getDefaultEntityData(action.payload.type)
    )
    .switchMap((entity) => { //                                     <------ switchMap here
        return  Observable.throw("testing only");
        /*if (entity) {
             entity.title = entity.type;
             return this.httpService.addEntity(entity);
        }*/
    })
    .catch((error) =>
        Observable.throw(new createEntityFailure(error)) //         <------ throw here
    )
    .map((mappedResponse) => 
        ({ type: CREATE_ENTITY_SUCCESS, payload: mappedResponse })
    );

Upvotes: 1

Everest
Everest

Reputation: 607

You can either split this up into multiple actions or just add another API call in the same effect using Observable.forkJoin

       @Effect() createEntity$ = this.actions$.ofType(CREATE_ENTITY)
.switchMap((action: CreateEntity) => {
    return Observable.forkJoin(
       this.httpService.callOne(),
       this.httpService.callTwo()
    )
    .catch((error) => Observable.of(new createEntityFailure(error)))
    .map(mappedResponse => ({ type: CREATE_ENTITY_SUCCESS, payload: mappedResponse }))
});

As forkJoin is parallel that won't work for you. You can just switchMap on the first API call and return the second:

       @Effect() createEntity$ = this.actions$.ofType(CREATE_ENTITY)
.switchMap((action: CreateEntity) => {
    return this.httpService.callOne();
 })
 .switchMap((response) => {
    return this.httpService.callTwo()
      .map(secondResponse => ({ 
          type: CREATE_ENTITY_SUCCESS,
          payload: {
              first: response, 
              second: secondResponse
          } 
       }))
 })
    .catch((error) => Observable.of(new createEntityFailure(error)))
});

Upvotes: 1

Tsvetan Ovedenski
Tsvetan Ovedenski

Reputation: 3518

How about this:

this.actions$
    .ofType(CREATE_ENTITY)
    .map((action: CreateEntity) => action.payload)
    .switchMap(payload =>
      this.httpService.getDefaultEntityData(payload.type)
        .mergeMap(entity => this.httpService.addEntity(entity))
        // .mergeMap(entity => Observable.throw('error')) // or this for testing
        .mergeMap(response => new actions.Action(...))
        .catch(error => new actions.Error(...))
    );

Upvotes: 1

Related Questions