[x] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
There is no action, no function which fired when all effects are settled up. Where we can dispatch actions to fire other effects.
this.onInit$ = this.actions$
.ofType('@ngrx/effects/up')
.switchMap((isAuthorized) => {
return this.isAuthorized$;
})
.map((isAuthorized) => {
if (isAuthorized) {
this.store.dispatch({ type: '[posts] getAll' })
}
});
@Effect()
this.onGetPosts$ = this.actions$
.ofType('[posts] getAll')
.map(() => ... )
or, may be
public ngrxOnRunEffects(resolvedEffects$: Observable<EffectNotification>): Observable<EffectNotification> {
this.isAuthorized$
.take(1)
.subscribe({
next: (isAuthorized) => {
if (isAuthorized) {
this.store.dispatch({ type: '[posts] getAll' })
}
},
});
return resolvedEffects$;
}
There a few issues, of @ngrx/store/init action. Seems, that this action is not useful for described purpose anymore. So, we probably need another.
ngrx v4
Possible workaround:
dispatch action, somewhere after application start.
In the AppComponent for example.
this.store.dispatch({ type: '[app] init' });
And use it to dispatch other actions, that must be dispatched after all effects are settled up.
Not sure why this would be needed. Have you tried the following operator:
this.onInit$ = this.actions$
.ofType(Actions.REESTABLISH)
.startWith(new Actions.ReestablishAction()) // This triggers the specified action on load.
.switchMap((isAuthorized) => {
return this.isAuthorized$;
})
.map((isAuthorized) => {
if (isAuthorized) {
this.store.dispatch({ type: '[posts] getAll' })
}
});
@wesselvdv
What is Actions.REESTABLISH and Actions.ReestablishAction?
I don't see such variables in ngrx's Actions.
Also, I don't think, that I need to initialize first value in stream with startWith.
I need values from this.isAuthorized$, but this observable must wait until ngrx/effects are up.
I can write that in the service constructor
this.isAuthorized$
.take(1)
.subscribe({
next: (isAuthorized) => {
if (isAuthorized) {
this.store.dispatch({ type: '[posts] getAll' })
}
},
});
[posts] getAll action fill be fired. But it must trigger an event, and no events are listening yet.
@ValeryVS Those are placeholder action classes. You're using strings as actions, while the accepted way to define an action is using a class with a type parameter that contains a string.
Something like this from the example app:
export class LoginAction implements Action {
readonly type = LOGIN;
constructor(public payload: Authenticate) {}
}
Doing it like above gives you type checking on the payload. I just used a placeholder that follows that convention.
Anyhow, back on topic; where is isAuthorized coming from? Is that an initial state defined in a reducer? What is it?
@wesselvdv
Yes, initial state of isAuthorized is defined in a reducer.
Now I wrote this
@Effect({ dispatch: false })
this.onInit$ = this.actions$
.ofType('[app] init')
.switchMap(() => this.isAuthorized$)
.map((isAuthorized) => {
if (isAuthorized) {
this.accountService.fetchAll();
this.imgService.fetchAll();
this.personService.fetchAll();
this.roleService.fetchAll();
}
});
public init() {
this.store.dispatch({ type: '[app] init' });
}
It works, but I need to laucn init() function in AppComponent. Through that I will know, when app is started and all ngrx effects are listen.
I suggest to make action, that will be dispatched automatically.
Before v4 it was init event https://github.com/ngrx/platform/issues/103#issue-243915851, but now it isn't.
That's way too complicated for this. The only thing you want is the initial state of a reducer, and you want to fire a boatload of actions based off it.
You can get the current state of a reducer using an operator:
@Effect()
this.onInit$ = this.actions$
.ofType('[app] init')
.startWith('[app] init')
.withLatestFrom(this.store.select(state => state.isAuthorized)) // < ---- Not sure where your prop is exactly.
.map(([, isAuthorized]) => {
if (isAuthorized) {
this.accountService.fetchAll();
this.imgService.fetchAll();
this.personService.fetchAll();
this.roleService.fetchAll();
}
});
Where you'll need to inject the store in your constructor as you would normally do to access a state from anywhere.
I will accept a PR that adds an "Root Effects Init" action that gets dispatched after the root effects have been started.
@tdeschryver any movement on this?
@brandonroberts Didn't change anything since last time.
The problem is that I'm not 100% certain about the solution.
Is it OK to open a PR and take if from there?
@tdeschryver yes, that's fine.
Most helpful comment
Not sure why this would be needed. Have you tried the following operator: