抱歉,仍然有任何疑问。我有一个要求用户必须完成6个步骤才能完成1个活动的要求。如果用户单击步骤6的URL,那么我首先必须检查他们是否已完成前面的5个步骤。如果没有,那么我必须指出用户已经完成了哪些步骤,哪些尚未完成。对于待处理的邮件,我还要添加URL,以便用户可以轻松地重定向。
问题是,我正在遍历每个步骤,但是由于NG RX,它没有等待Action完成并转到下一步。我无法确定以前的步骤是否真的完成了。
我正在使用NG RX动作,减速器和效果技术。无论如何,我可以等待循环完成第一个动作。一旦完成第一项操作,然后从数组中获取第二个元素。
// This is part of code in effect file.
const steps = [Step.Step1, Step.Step2, Step.Step3]
// It should take next element once evaluation of step1 is completed.
steps.every((currentStep: Step) => {
currentDependentStep = currentStep;
switch (currentStep) {
case Step.Step1:
this.store.dispatch(new fromSomeAction.SomeAction1);
this.store.dispatch(new fromSomeAction.SomeAction2);
this.store.combineLatest(
this.store.select(fromApp.getData1),
this.store.select(fromApp.getData2)
).first(([payload, data1, data2]) => !!data1 && !!data2)
.subscribe(([payload, data1, data2]) => {
// It should not take second element till I get below result whethere it is completed or not.
isCompleted = <check for some condition>;
});
break;
case Step.Step2:
this.store.dispatch(new fromSomeAction.SomeAction1);
this.store.dispatch(new fromSomeAction.SomeAction2);
this.store.combineLatest(
this.store.select(fromApp.getData1),
this.store.select(fromApp.getData2)
).first(([payload, data1, data2]) => !!data1 && !!data2)
.subscribe(([payload, data1, data2]) => {
isCompleted = <check for some condition>;
});
break;
case Step.Step3:
this.store.dispatch(new fromSomeAction.SomeAction1);
this.store.dispatch(new fromSomeAction.SomeAction2);
this.store.combineLatest(
this.store.select(fromApp.getData1),
this.store.select(fromApp.getData2)
).first(([payload, data1, data2]) => !!data1 && !!data2)
.subscribe(([payload, data1, data2]) => {
isCompleted = <check for some condition>;
});
break;
break;
default:
isCompleted = false;
break;
}
return !isCompleted;
});
// Call completed action with payload based on isCompleted
注意:抱歉,我没有实际的代码可在此处分享。
答案 0 :(得分:1)
我认为最好的方法是通过路由器防护,请参阅example-app作为示例。
@Injectable({
providedIn: 'root',
})
export class BookExistsGuard implements CanActivate {
constructor(
private store: Store<fromBooks.State>,
private googleBooks: GoogleBooksService,
private router: Router
) {}
/**
* This method creates an observable that waits for the `loaded` property
* of the collection state to turn `true`, emitting one time once loading
* has finished.
*/
waitForCollectionToLoad(): Observable<boolean> {
return this.store.pipe(
select(fromBooks.getCollectionLoaded),
filter(loaded => loaded),
take(1)
);
}
/**
* This method checks if a book with the given ID is already registered
* in the Store
*/
hasBookInStore(id: string): Observable<boolean> {
return this.store.pipe(
select(fromBooks.getBookEntities),
map(entities => !!entities[id]),
take(1)
);
}
/**
* This method loads a book with the given ID from the API and caches
* it in the store, returning `true` or `false` if it was found.
*/
hasBookInApi(id: string): Observable<boolean> {
return this.googleBooks.retrieveBook(id).pipe(
map(bookEntity => BookActions.loadBook({ book: bookEntity })),
tap(action => this.store.dispatch(action)),
map(book => !!book),
catchError(() => {
this.router.navigate(['/404']);
return of(false);
})
);
}
/**
* `hasBook` composes `hasBookInStore` and `hasBookInApi`. It first checks
* if the book is in store, and if not it then checks if it is in the
* API.
*/
hasBook(id: string): Observable<boolean> {
return this.hasBookInStore(id).pipe(
switchMap(inStore => {
if (inStore) {
return of(inStore);
}
return this.hasBookInApi(id);
})
);
}
/**
* This is the actual method the router will call when our guard is run.
*
* Our guard waits for the collection to load, then it checks if we need
* to request a book from the API or if we already have it in our cache.
* If it finds it in the cache or in the API, it returns an Observable
* of `true` and the route is rendered successfully.
*
* If it was unable to find it in our cache or in the API, this guard
* will return an Observable of `false`, causing the router to move
* on to the next candidate route. In this case, it will move on
* to the 404 page.
*/
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
return this.waitForCollectionToLoad().pipe(
switchMap(() => this.hasBook(route.params['id']))
);
}
}
托德·莫托(Todd Motto)在ultimatecourses上也有一篇关于该主题的精彩文章。