5
votes

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.

1
Rather than just describing the code, please include it in the question.cartant
I have added come code.bucicimaci
yes, dispatching the action in the resolver is a better approach. The component will not wait for the data, It will just render. Also share your Effects and Reducer code.pTK

1 Answers

1
votes

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.
    });
}