Store: Action Handler not getting executed.

Created on 7 Apr 2018  ·  16Comments  ·  Source: ngxs/store

Versions

* ngxs: 3.0.0-dev.bcbc16f
* @angular/core:  6.0.0-rc.3

Repro steps

Observed behavior

no "New Login!......." log message printed

Desired behavior

expected to see "New Login!......." log in the console.

Mention any other details that might be useful (optional)

https://xmlking.github.io/nx-starter-kit/index.html

Most helpful comment

I'm having similar difficulties with action handlers. It seems it is not enough to just create the action handler and install it into the providers collection. You actually have to inject the action handler into something so it will be instantiated at least once by DI.

So I think the question here is... How does the action handler injectable get picked up by the system? It has to be injected into something at least once to get instantiated by DI. I put it on my constructor of my State class. Not sure if this is "correct" but it is working.

The action handler documentation needs to be enhanced telling us just how the injectable action handler is plugged into the system.

All 16 comments

I'm having similar difficulties with action handlers. It seems it is not enough to just create the action handler and install it into the providers collection. You actually have to inject the action handler into something so it will be instantiated at least once by DI.

So I think the question here is... How does the action handler injectable get picked up by the system? It has to be injected into something at least once to get instantiated by DI. I put it on my constructor of my State class. Not sure if this is "correct" but it is working.

The action handler documentation needs to be enhanced telling us just how the injectable action handler is plugged into the system.

May be better to add it to foorRoot() and forFeature()?

"May be better to add it to foorRoot() and forFeature()?"

I was thinking the same thing. What I did to get it to work feels like a hack.

Maybe another parameter on the current forRoot or forFeature that takes an array of action handler types.

NgxsModule.forRoot([], [RouteHandler])

Since these feel like effects maybe a ActionHandlerModule with a forRoot/forFeature that takes an array of action handler types. But this feels like overkill as there is no real need for a ActionHandlerModule.

NgxsActionHandlerModule.forRoot([RouteHandler])

Odd....I'm using this a lot and not had this issue.

amcdnl,

Can you share how you set up your action handler? Maybe you dug some secret nugget out of the documents that I'm missing.

Thanks for the example. You are taking the second approach the documentation is showing. But if you follow the first example of putting action listeners in an Injectable class, that injectable class has to be injected somewhere before the constructor will run and start listening for actions. So in the least this first approach is a bad example or an incomplete one.

I switched over to the second approach of putting my action listeners on the component itself like your example.

Unless it is the AppComonent, components can be destroyed and recreated as you navigate around and having it in a component can cause multiple subscriptions (unless you make sure to unsubscribe when the component is destroyed).

I didn't want to deal with that so I inject the action handlers into the constructor of my states and then doing nothing with them.

I should have clarified... yes the AppComponent is where I have them. Neither approach is pretty in my opinion and I'd like to get some guidance from the ngxs team.

I have a suggestion to possibly improve the second approach in the docs. I think it could/should be done using the Store.

Something like this:

@Component({ ... })
export class CartComponent {
  constructor(private store: Store) {}
 
  ngOnInit() {
    this.store.action<CartDeleteSuccess>().subscribe(() => alert('Item deleted'));
  }
}

This would take care of running this.actions$.pipe(ofAction(CartDeleteSuccess)) and return the observable.

I agree. Neither are desirable. I like the approach you suggested. Either have another module (NgxsActionHandlerModule) to import and create the action handlers, or allow for another parameter in NgxsModule.forRoot() and NgxsModule.forFeature() to allow us to pass in action handlers.

I've talked to Austin about it and we haven't really figured out how our version of ngrx@Effects will look like.

But I did come up with a good way to initialize services by using APP_INITIALIZER.

I've created a demo for you, and until we figure out how to best tackle the action handlers, you will have to include your own HandlerModule.

https://stackblitz.com/edit/ngxs-action-handlers?file=app%2Fhandler.module.ts

Open the console and you should see how all the stuff gets initialized properly.

I'm going to close this issue now, since we have found a solution to the problem.
But keep your eyes open and we might find a better solution later on.

@leon - Can you add this to the docs?

I've tried the APP_INITIALIZER approach and I'm getting "Cannot instantiate cyclic dependency! ApplicationRef" Error.

It happens when the handler needs Router to be injected...

https://stackblitz.com/edit/ngxs-action-handlers-qbjub9

The router can't be injected directly into your handler. Inject Injector. And then right before you need the router, use the Injector to inject the router.

This is great to come across, because I'm a bit new to angular and the docs still show that you inject Router into the handler. Very frustrating.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

un33k picture un33k  ·  4Comments

ToxicToast picture ToxicToast  ·  6Comments

kyusupov33 picture kyusupov33  ·  3Comments

am4apps picture am4apps  ·  4Comments

paulstelzer picture paulstelzer  ·  5Comments