π Listening for Actions in @ngrx/store π
The Problem
You need to run some code after a particular action has been fired.
For example, you want to reset a form after the ADD_STORY_SUCCESS
action has been fired.
The Solutions
π€ Add New Key
Add one more key to your state.
{
isSuccess: boolean
}
Then you can listen to changes like this:
this.store.select(state => state.story.isSuccess)
.filter(v => !!v)
.subscribe(() => this.form.reset())
I do not like this solution because I have to maintain another key
in my store and every time worry about resetting it.
π Subscribe to Effect
If you are working with ngrx/effects
you can inject the effect
into your component and subscribe to him.
For example:
@Effect() addStory$ = this.actions$
.ofType('ADD_STORY')
.switchMap(action => this.storyService.add(action.payload)
.map(story => ({
type: 'ADD_STORY_SUCCESS'
}))
)
Then in your component:
constructor( private storyEffects : StoryEffects) {}storyEffects.addStory$
.filter(action => action.type === 'ADD_STORY_SUCCESS')
.subscribe(res => this.form.reset());
There are two dilemmas with this approach:
- Maybe you do not work with
ngrx/effects
.
2. You need to use the share
operator. Otherwise, you will have two subscriptions. (i.e., two HTTP calls in this case)
@Effect() addStory$ = this.actions$
.ofType('ADD_STORY')
.switchMap(action => this.postsService.add(action.payload)
.map(story => ({
type: 'ADD_STORY_SUCCESS'
}))
).share()
πͺ Subscribe to the Dispatcher
You may not know that, but every action goes through a service called Dispatcher
. The Dispatcher is a Subject
which means it is observable.
If we want to be notified when actions are fired, we can subscribe to the Dispatcher
in our component.
constructor(private dispatcher: Dispatcher) {}dispatcher.filter(action => action.type === 'ADD_STORY_SUCCESS')
.subscribe(() => this.form.reset())
I took a step further and created a more comfortable syntax.
@Injectable()
export class AppActions {
_actions = new Subject<Action>();
ofType( type : string ) {
return this._actions.filter(( action : Action )
=> action.type === type);
}
nextAction( action : Action ) {
this._actions.next(action);
}
}
@Injectable()
export class MyDispacther extends Dispatcher {
constructor( private actions: AppActions ) {
super();
}
next( action: Action ) {
super.next(action);
this.actions.nextAction(action);
}
}
I am extending the original Dispatcher
and using a new Subject
to create a slightly cleaner syntax.
We also need to tell Angular to use our Dispatcher
instead of the original.
providers: [{ provide: Dispatcher, useClass: MyDispacther }]
Now in our component we can write the following code:
constructor( private actions : AppActions) {}actions.ofType('ADD_STORY_SUCCESS')
.subscribe(() => this.form.reset())
We will see in a future article, how it can help us when I talk about connecting your forms to ngrx/store
.
ngrx-generator
On this occasion, I would like to present you with a new tool that I have been working on lately that will save you the headache of all the Redux boilerplate.