如何使用角度路由器防护装置附加ngrx/store

Mar*_*nck 10 angular2-routing ngrx ngrx-effects angular

我是ngrx/store的初学者,这是我使用它的第一个项目.

我已经使用ngrx/store成功设置了我的角度项目,并且我可以在初始化主要组件后调度一个加载操作,如下所示:

ngOnInit() { this.store.dispatch({type: LOAD_STATISTICS}); }

我已设置一个效果,以便在调度此操作时加载数据:

@Effect()
loadStatistik = this.actions.ofType(LOAD_STATISTICS).switchMap(() => {
    return this.myService.loadStatistics().map(response => {
        return {type: NEW_STATISTICS, payload: response};
    });
});
Run Code Online (Sandbox Code Playgroud)

我的减速机看起来像这样:

reduce(oldstate: Statistics = initialStatistics, action: Action): Statistik {
    switch (action.type) {
        case LOAD_STATISTICS:
            return oldstate;
        case NEW_STATISTICS:
            const newstate = new Statistics(action.payload);

            return newstate;
    ....
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但我无法理解如何使用路由器防护,因为我目前只需要调度一次LOAD_ACTION.

此外,组件必须调度LOAD操作,加载初始数据对我来说听起来不对.我希望商店本身知道它需要加载数据,我不必先调度一个动作.如果是这种情况,我可以删除组件中的ngOnInit()方法.

我已经查看了ngrx-example-app,但我还没有真正了解它是如何工作的.

编辑:

添加一个返回ngrx-store observable的解析防护后,该路由不会被激活.这是决心:

   @Injectable()
  export class StatisticsResolver implements Resolve<Statistik> {
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Statistik> {
        // return Observable.of(new Statistik());
        return this.store.select("statistik").map(statistik => {
        console.log("stats", statistik);

        return statistik;
    });
}
Run Code Online (Sandbox Code Playgroud)

这是路线:

const routes: Routes = [
    {path: '', component: TelefonanlageComponent, resolve: {statistik:  TelefonieStatistikResolver}},
];
Run Code Online (Sandbox Code Playgroud)

not*_*Dev 7

我不太明白为什么要通过解析器将已解析的数据发送到组件.设置ngrx存储的关键是拥有单一的数据源.所以,你想在这里做的是确保数据是真的.休息时,组件可以使用选择器从商店获取数据.

我可以看到你是LOAD_ACTIONngOnInit组件的方法调用的.您无法调用操作来解析数据,然后该数据会导致Init您调用该操作的组件!这就是您的路由器未加载路由的原因.

不确定你是否明白这一点,但这是有道理的!

简单来说,你在做什么就是这个.您正在锁定房间,然后将钥匙推过门下方的缝隙,然后想知道为什么门没有打开.

随身携带钥匙!

守卫的解决方法应该调用LOAD_ACTION.然后解决方案应该等待数据加载,然后路由器应该继续到组件.

你是怎样做的?

其他答案是设置订阅,但问题是你不想在你的警卫中这样做.订阅警卫并不是一个好习惯,因为他们需要取消订阅,但如果数据没有得到解决,或者警卫返回错误,那么路由器永远不会取消订阅而且我们弄得一团糟.

所以,使用take(n).此运算符将从n订阅中获取值,然后自动终止订阅.

此外,在你的行动中,你需要LOAD_STATISTICS_SUCCESS和a LOAD_STATISTICS_FAIL.由于您的服务方法可能会失败!

在reducer中State,您需要一个loaded属性,该属性true在服务调用成功并调用LOAD_STATISTICS_SUCCESSaction 时转向.

在主减速器中添加一个选择器,getStatisticsLoaded然后在你的gaurd中,你的设置将如下所示:

resolve(): Observable<boolean> {

this.store.dispatch({type: LOAD_STATISTICS});

return this.store.select(getStatisticsLoaded)
    .filter(loaded => loaded)
    .take(1);
Run Code Online (Sandbox Code Playgroud)

}

因此,只有当loaded属性更改为true时,filter才会允许该流继续.take将取第一个值并传递.此时解析完成,路由器可以继续.

再次,take将杀死订阅.


Mar*_*nck 6

在AngularFrance提供宝贵意见后,我自己解决了这个问题.由于我还是初学者,我不知道这是否应该如何完成,但它确实有效.

我像这样实现了一个CanActivate Guard:

@Injectable()
export class TelefonieStatistikGuard implements CanActivate {
    constructor(private store: Store<AppState>) {}

    waitForDataToLoad(): Observable<Statistik> {
        return this.store.select(state => state.statistik)
            .filter(statistik => statistik && !statistik.empty);
    }

    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
        this.store.dispatch({type: LOAD_STATISTIK});

        return this.waitForDataToLoad()
            .switchMap(() => {
                return Observable.of(true);
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

方法canActivate(...)首先调度一个动作来加载数据.在waitForDataToLoad()中,我们过滤数据已经存在但不为空(我的业务逻辑的实现细节).

返回true后,我们调用switchMap返回一个Observable为true.