Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dispatch ngrx store action in route resolver

I'm currently have a container (stateful) component which dispatches a select and a get action based on a route param (id) in the ngOnInit method. The point of these actions to have the data and the selected id in my store.

I'm curious would it be correct to dispatch these actions in a resolver?

Thanks for the replies.

My component:

@Component({
  selector: 'app-container',
  templateUrl: './container.component.html',
  styleUrls: ['./container.component.css']
})
export class ContainerComponent implements OnInit, OnDestroy {

  private componetDestroyed$ = new Subject();

  constructor(private store: Store<fromRoot.State>, private route: ActivatedRoute) { }

  ngOnInit() {
    this.route.params
      .filter(params => params['id'])
      .map(params => params['id'])
      .takeUntil(this.componetDestroyed$)
      .subscribe(id => {
        this.store.dispatch(new GetAction(id));
        this.store.dispatch(new SelectAction(id));
      });
  }

  ngOnDestroy() {
    this.componetDestroyed$.next();
    this.componetDestroyed$.unsubscribe();
  }   
}

My routes:

[{
  path: ':id',
  component: ContainerComponent
}]

The resolver would be:

@Injectable()
class MyResolver implements Resolve<any> {

constructor(private store: Store<fromRoot.State>) {}

resolve(route: ActivatedRouteSnapshot, state: RouteStateSnapshot) {
  let id = route.params['id'];
  this.store.dispatch(new SelectAction(id));
  this.store.dispatch(new GetAction(id));
  return null;
}

And the modified routes:

[{
  path: ':id',
  component: ContainerComponent,
  resolve: {
    store: MyResolver
  }
}]

And that's why I'm not sure this is correct, becuase the store will always be null.

like image 887
bucicimaci Avatar asked Nov 08 '22 22:11

bucicimaci


1 Answers

There is nothing wrong with the way how you dispatch actions in ngOnInit based on this.route.params.

What is important is that the resolvers are data providers for routes. And if you don't provide data then you are using them wrongly.

In you case it sounds more like a canActivate guard that is responsible to emit actions and allow the route.


Nevertheless you could extend the resolver to selecting data you want.

@Injectable({
    providedIn: 'root',
})
export class DataResolver implements Resolve<number> {
    constructor(private store: Store) {
    }

    public resolve(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ): Observable<any> {
        this.store.dispatch(LoadDataForMyRoute());

        return this.store.pipe(
            select(dataForMyRoute),
            filter(data => !!data), // <- waiting until data is present
            take(1), // <- important to add
        );
    }
}

and in your component you can access it like that instead of this.store.select.

constructor(
    protected readonly store: Store,
    protected readonly activatedRoute: ActivatedRoute,
) {}

public ngOnInit(): void {
    this.activatedRoute.data.subscribe(data => {
        // everything is here.
    });
}
like image 139
satanTime Avatar answered Nov 14 '22 21:11

satanTime