Reputation: 15064
In my sample Angular 2 application , I am using ngrx/store and ngrx/effects for state management.
Below is one of the function in a component to add a new item.
addAuthor() {
this.store.dispatch(addAuthorAction(this.fg.value));
console.log('2')
}
In the above code this.store.dispatch(addAuthorAction(this.fg.value));
takes care of making an AJAX call to server and adding a new author to
database, which is working fine.
And because this.store.dispatch(addAuthorAction(this.fg.value));
is an async
action , console.log("2")
statement gets executed even before the AJAX call
is completed.
My question is , what needs to be modified so that console.log gets executed after store.dispatch is done.
Upvotes: 24
Views: 45055
Reputation: 891
The accepted answer is correct, but I find the accepted answer is missing an expanded example.
private destroyRef = inject(DestroyRef);
submitToServer(formData): Observable<any> {
const correlationid = ...;
setTimeout(() => {
this.store.dispatch(
userActions.FETCH_USER({ correlationid }),
);
});
return this.actions$.pipe(
ofType(userActions.FETCH_USER_SUCCESS),
filter((action) => action.correlationid === correlationid)
tap((action) => {
console.log('2');
console.log('FETCH_USER_SUCCESS', action);
}),
takeUntilDestroyed(this.destroyRef),
);
}
Summary:
Upvotes: 0
Reputation: 33
Today I have similar issue and I use tap() to solve this. When are you on your effect import tap from "rxjs/operators"
import { tap } from "rxjs/operators";
and next use it in your switchMap after map operation on SuccessAction
this.service.save(option).pipe(
map((result) => action.saveSuccess({ option: option})),
tap(() => this.router.navigate(['link'])),
catchError((error) => of(actions.saveError({ error }))
this code work form me.
Upvotes: 0
Reputation: 2125
As dispatch is asynchronous (fire and forget), we can subscribe to the returned observable object and then execute the next statement once we get hold of observable object.
addAuthor() {
this.store.dispatch(addAuthorAction(this.fg.value))
.subscribe(() => {
console.log('2')
});
}
Alternatively,
myObservableObject$: Observable<any>;
this.myObservableObject$ = this.store.dispatch(addAuthorAction(this.fg.value));
this.myObservableObject$.subscribe((response) => {
console.log('2')
});
The above is per ngxs state management framework. More @ https://www.ngxs.io/advanced/actions-life-cycle#asynchronous-actions
Upvotes: -4
Reputation: 23803
Quick answer : You can't.
As you said, dispatch
is asynchronous.
What you should do is use @ngrx/effects. It's nearly the same as using addAuthorAction
except that instead of calling a function, you "catch" the dispatched actions and do something just after they've been applied by the reducers.
So what I do in general, is that I divide my actions in 3, for example :
FETCH_USER
FETCH_USER_SUCCESS
FETCH_USER_ERROR
FETCH_USER
is just used to toggle a boolean so I can display a spinner while fetching the user
I catch this action from an effect and make an http request to fetch the user
If the http response is OK and I have the info I'm looking for, I dispatch from the effect FETCH_USER_SUCCESS
with the response as payload, otherwise I dispatch FETCH_USER_ERROR
and I toggle the boolean to false (so we can try to fetch him again for example).
So in your example, if you want to console.log
something AFTER the FETCH_USER_SUCCESS, just use another effect to catch the FETCH_USER_SUCCESS and do what you want to here.
Upvotes: 24
Reputation: 57026
With ngrx you can listen to actions like this:
constructor(private actionsSubject$: ActionsSubject, private store: Store<AppState>) {}
ngOnInit() {
this.actionsSubject$.pipe(
takeUntil(this.unsubscribe$), // optional
filter((action) => action.type === SimsActionTypes.SimEditedSuccess)
).subscribe(({payload}) => {
console.log(payload)
)
}
When you dispatch FIRST_ACTION use an effect to make the HTTP request. In the effect, when you have the response back, fire off a SECOND_ACTION with the response as the payload. Then just listen for SECOND_ACTION in your controller .ts file
Upvotes: 7
Reputation: 6760
Tested with
"@ngrx/core": "^1.2.0",
"@ngrx/effects": "^7.4.0",
"@ngrx/router-store": "^7.4.0",
"@ngrx/store": "^7.4.0",
"@ngrx/store-devtools": "^7.4.0",
This will also work:
import { ofType, Actions } from '@ngrx/effects';
// Constructor
constructor(
private _actions$: Actions,
private _store: Store<any>,
) { }
// YOUR METHOD
this._store.dispatch(<ACTION>);
this._actions$.pipe(ofType(<ACTION_NAME>)).subscribe((data: any) => {
console.log(data); // returned state data
})
Upvotes: 18