Route Guard 加载 ngrx 存储数据仅在第二次单击后导航到受保护的路由
Route Guard loading ngrx store data only navigates to protected route after second click
为了在加载实际组件之前将数据从后端加载到我的 ngrx 存储中,我在路由的 canActivate
属性中使用了路由保护。
{path: 'my-route', component: MyRouteComponent, canActivate: [LoadDataGuardService]}
如果相应的数据已经可用,守卫应该检查商店。如果没有,它应该从后端加载到商店中。一旦数据在存储中,就应该打开路由(第一次点击)。这是我的 Guard 的 canActivate
方法。
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const loadedTasks = this.store.pipe(select(selectTaskMap))
.pipe(map(taskMap => Object.keys(taskMap).length > 0));
loadedTasks
.pipe(
take(1),
filter(loaded => !loaded),
map(() => this.store.dispatch(GetTasks())))
.subscribe(() => this.store);
return loadedTasks
.pipe(take(1));
}
在第一次点击时将数据加载到商店中。但是如果必须加载数据,我必须再次单击 link 才能导航到所需的视图。似乎第一次点击只加载数据,但在成功加载数据后没有 return 一个 True
的 Observable。
如何调整代码将数据加载到store中,并在第一次点击数据到store时立即打开路由?
编辑:
这里有一个用于复制的 stackblitz 工作示例:Stackblitz Link
可以清楚的看到,第二次点击 Activate Route
link.
后,路由组件的内容才显示出来
为了在测试时清除商店,我添加了一个按钮。
看来问题是第一次任务还没有加载。
尝试将 first
移到 filter
之后。
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Store, select } from '@ngrx/store';
import {filter, tap, map, take} from 'rxjs/operators';
import { selectEntityMap } from './store/selectors/entity.selectors';
import { AppState } from './store/state/app.state';
import { GetEntity } from './store/actions/entity.actions';
@Injectable({
providedIn: 'root'
})
export class LoadDataGuardService implements CanActivate {
constructor(public router: Router, private store: Store<AppState>) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.store.pipe(select(selectEntityMap)).pipe(
map(taskMap => Object.keys(taskMap).length > 0),
tap(loaded => {
if (!loaded) { // checking if we need to dispatch the action.
this.store.dispatch(GetEntity());
}
}),
filter(loaded => !!loaded), // waiting until the tasks have been loaded.
take(1),
);
}
}
为了在加载实际组件之前将数据从后端加载到我的 ngrx 存储中,我在路由的 canActivate
属性中使用了路由保护。
{path: 'my-route', component: MyRouteComponent, canActivate: [LoadDataGuardService]}
如果相应的数据已经可用,守卫应该检查商店。如果没有,它应该从后端加载到商店中。一旦数据在存储中,就应该打开路由(第一次点击)。这是我的 Guard 的 canActivate
方法。
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const loadedTasks = this.store.pipe(select(selectTaskMap))
.pipe(map(taskMap => Object.keys(taskMap).length > 0));
loadedTasks
.pipe(
take(1),
filter(loaded => !loaded),
map(() => this.store.dispatch(GetTasks())))
.subscribe(() => this.store);
return loadedTasks
.pipe(take(1));
}
在第一次点击时将数据加载到商店中。但是如果必须加载数据,我必须再次单击 link 才能导航到所需的视图。似乎第一次点击只加载数据,但在成功加载数据后没有 return 一个 True
的 Observable。
如何调整代码将数据加载到store中,并在第一次点击数据到store时立即打开路由?
编辑:
这里有一个用于复制的 stackblitz 工作示例:Stackblitz Link
可以清楚的看到,第二次点击 Activate Route
link.
后,路由组件的内容才显示出来
为了在测试时清除商店,我添加了一个按钮。
看来问题是第一次任务还没有加载。
尝试将 first
移到 filter
之后。
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Store, select } from '@ngrx/store';
import {filter, tap, map, take} from 'rxjs/operators';
import { selectEntityMap } from './store/selectors/entity.selectors';
import { AppState } from './store/state/app.state';
import { GetEntity } from './store/actions/entity.actions';
@Injectable({
providedIn: 'root'
})
export class LoadDataGuardService implements CanActivate {
constructor(public router: Router, private store: Store<AppState>) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.store.pipe(select(selectEntityMap)).pipe(
map(taskMap => Object.keys(taskMap).length > 0),
tap(loaded => {
if (!loaded) { // checking if we need to dispatch the action.
this.store.dispatch(GetEntity());
}
}),
filter(loaded => !!loaded), // waiting until the tasks have been loaded.
take(1),
);
}
}