Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5: NGXS & route resolvers

Tags:

angular

ngxs

Is it possible to user route resolvers with the NGXS store?

I have a test made like this, but I don't know if it is the correct way to go:

import {ActivatedRouteSnapshot, Resolve} from "@angular/router";
import {Todo} from "./todos.models";
import {Observable} from "rxjs/Observable";
import {Select, Store} from "@ngxs/store";
import {GetTodo, TodosState} from "./todos.state";
import {Injectable} from "@angular/core";

@Injectable()
export class TodoResolver implements Resolve<Todo> {

    constructor(
        private store:Store
    ) {}

    @Select(TodosState.getTodo)
    private todo$:Observable<Todo>;

    resolve(route:ActivatedRouteSnapshot): Observable<Todo>
    {
        const id = <number><any> route.paramMap.get('id');
        this.store.dispatch(new GetTodo(id));
        return this.todo$;
    }
}

When I try this, the application just hangs. No errors shown.

All help welcome. Thanks

like image 795
rauwebieten Avatar asked Nov 09 '18 10:11

rauwebieten


2 Answers

Ignore please, I found the solution myself...

Changed code to:

@Injectable()
export class TodoResolver implements Resolve<Todo> {

    constructor(
        private store:Store
    ) {}

    resolve(route:ActivatedRouteSnapshot): Observable<Todo>
    {
        const id = <number><any> route.paramMap.get('id');
        this.store.dispatch(new GetTodo(id));

        return this.store.selectOnce(TodosState.getTodo);
    }
}
like image 79
rauwebieten Avatar answered Oct 22 '22 15:10

rauwebieten


I think rauwebieten's solution only works for sync action. Async action will modify the store after selectOnce's execution.

I have to set up two states to deal with async actions. One is Todos State and another is RequestingTodo State.

The code looks like:

@Injectable()
export class AsyncTodoResolver implements Resolve<Todo> {
    @Select(RequestingTodoState)
    private todo$:Observable<Todo>;

    constructor(
        private store:Store
    ) {}

    resolve(route:ActivatedRouteSnapshot): Observable<Todo> {
        const id = <number><any> route.paramMap.get('id');
        return this.store.dispatch(new GiveOrFetchTodo(id))
           .pipe(
              withLatestFrom(todo$),
              map([any, todo]) => {return todo;}
            );
    }
}
like image 2
Shuai Wang Avatar answered Oct 22 '22 14:10

Shuai Wang