I'm reaching you here about ngrx effects, what i am tryign to do is to have a function login that distpatch an action type login and an effect on this action will user my service to make api call. After this return token, i want to dispatch two other action one of type getUserMenu and one of type getUserInfo. Those two action will be of different type and have different effect.
I have 3 stores at the end: one for token and auth one for user info one for menu info
i tried things like that :
login = createEffect(
() =>
this.actions$
.pipe(
ofType(authLogin),
tap(action => {
console.log("EFFECT LOGINNNN");
return this.authService.postLogin(action.username,
action.password).pipe(
map((data: any) => {
console.log("AUTHTHHTHTH DATATA ", data);
let props = data.token;
let payload = {
token: data.token,
isAuthenticated: true
}
this.store.dispatch(moMenuHttpGetListAction({US_ID: action.username}));
this.store.dispatch(userHttpGetInfoAction({US_ID:action.username}));
this.localStorageService.setItem(AUTH_KEY, payload);
}))
})
),
{ dispatch: true }
);
if i set dispatch false login work but no method called for getting user info and user menu but when i set dispatch true i have infinit loop on this same effect the action moMenuHttpGetListAction would look like that :
moMenuHttpGetListEffect = createEffect(
() => this.actions$.pipe(
ofType(moMenuHttpGetListAction),
switchMap(action => {
console.log("MOMENU LOGINNNN");
return this.moMenuService.getKmApplications(action.US_ID).pipe(
map((data: any) => {
console.log("MOMENU DATATA ", data);
console.log("MOMENU DATATA ", action.US_ID);
let payload = {
MO_MENU: data
}
this.store.dispatch(moMenuSetListAction({payload: data}));
this.localStorageService.setItem(MENU_KEY, payload);
}))
})
),
{ dispatch: false }
);
but on this one when i set dispatch to true , i got error compiling. and my action looks like :
import { createAction } from "@ngrx/store";
import { props } from "@ngrx/store";
import { MoMenu, MoMenuState } from "./mo_menu.models";
//TODO CHANGER ME_ID en US_ID
export const moMenuGetErrorAction = createAction("[User] Get Info");
export const moMenuGetIsLoadingAction = createAction("[User] Get Info");
export const moMenuSetErrorAction = createAction('[MoMenu] HTTP GET ACTION',
props<{error: string}>()
);
export const moMenuSetLoadingAction = createAction('[MoMenu] HTTP GET ACTION',
props<{loading: boolean}>()
);
export const moMenuHttpGetListAction = createAction('[MoMenu] HTTP GETLIST ACTION',
props<{US_ID: string}>()
);
export const moMenuHttpGetListErrorAction = createAction('[MoMenu] HTTP GET ACTION Error',
props<{error: any}>()
);
export const moMenuGetListAction = createAction("[MoMenu] Get List");
export const moMenuSetListAction = createAction("[MoMenu] Set Mo Menu List",
props<{payload: MoMenu[]}>());
export const moMenuDeleteAction = createAction("[MoMenu] Delete List");
those are the two reducers concerned as someone ask me to add :
Ngrx is kinda new to me so i'd love some help on this =)
import { AuthState } from './auth.models';
import { authLogin,
authLogout ,
authGetErrorAction,
authGetIsLoadingAction,
authSetErrorAction,
authSetIsLoadingAction
} from './auth.actions';
import { createReducer, on, Action } from '@ngrx/store';
export const initialState: AuthState = {
isAuthenticated: false,
token: undefined,
isLoading: false,
HttpResponse: undefined
};
const reducer = createReducer(
initialState,
on(authSetErrorAction, (state, { error }) => ({
...state, HttpResponse: error
})),
on(authSetIsLoadingAction, (state, { isLoading }) => ({
...state, isLoading: isLoading
})),
on(authLogin, state => ({ ...state, isAuthenticated: true })),
on(authLogout, state => ({ ...state, isAuthenticated: false }))
);
export function authReducer(
state: AuthState | undefined,
action: Action
): AuthState {
return reducer(state, action);
}
import { MoMenuState } from "./mo_menu.models";
import {
moMenuGetListAction,
moMenuDeleteAction,
moMenuHttpGetListAction,
moMenuSetListAction,
moMenuHttpGetListErrorAction,
moMenuGetErrorAction,
moMenuGetIsLoadingAction,
moMenuSetErrorAction,
moMenuSetLoadingAction
} from "./mo_menu.actions";
import { createReducer, on, Action } from "@ngrx/store";
export const initialState: MoMenuState = {
isLoading: false,
HttpResponse: undefined,
MoMenuItems: null
}
const reducer = createReducer(
initialState,
on(moMenuSetErrorAction, (state, { error }) => ({
...state, HttpResponse: error
})),
on(moMenuSetLoadingAction, (state, { loading }) => ({
...state, isLoading: loading
})),
on(moMenuHttpGetListErrorAction, (state, { error }) => (
undefined)),
on(moMenuSetListAction, (state, { payload }) => ({
...state, MoMenus: payload
})),
on(moMenuHttpGetListAction, (state, { US_ID }) => ({
...state
})),
on(moMenuGetListAction, state => state),
on(moMenuDeleteAction, state => state)
);
export function moMenuReducer(
state: MoMenuState | undefined,
action: Action
): MoMenuState {
return reducer(state, action);
}
If some of you guys have any idea for me ?
In this example, we use tap to perform the side effect itself, and pass “{dispatch: false}” to the “createEffect” function to indicate it does not need to dispatch anything after the side effect completes.
'ofType' filters an Observable of Actions into an observable of the actions whose type strings are passed to it.
} @ngrx/effects provides an Angular actions$ service (which is also an Observable ) to emit every action that has been dispatched by your application in a single stream. Its ofType() method can be used to filter the one or more actions we're interesting in before adding a side-effect.
Getting started. It will add and install the @ngrx/effects library to your package. json and scaffold your AppModule to import the NgRx EffectsModule into your application. With the setup complete, we can start modifying the app to introduce and handle some API calls using Effects.
This is how I'm dispatching multiple actions as a result of another action in NgRx 8:
@Injectable()
export class MyEffects {
myAction$ = createEffect(() =>
this.actions$.pipe(
ofType(myActions.firstAction),
switchMap(action => this.someService.getById(action.someId)),
switchMap((sth: Something) => [
myActions.firstActionSuccess({ payload: sth }),
myActions.secondAction({ payload: sth.xyz }),
// ... more actions
])
)
);
constructor(
private someService: SomeService,
private actions$: Actions
) { }
}
Actions look like this:
export const firstAction = createAction('First Action', props<{ someId: number }>());
export const firstActionSuccess = createAction('First Action Success', props<{ payload: Something }>());
export const secondAction = createAction('Second Action', props<{ payload: string }>());
Hope that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With