ngrx - for loop - взять следующий элемент после завершения процесса для текущего элемента - PullRequest
0 голосов
/ 14 мая 2019

извините за подоконник вопрос.У меня есть требование, когда пользователь должен выполнить 6 шагов, чтобы выполнить 1 действие.Если пользователь нажимает на URL шага 6, то сначала я должен проверить, закончили ли они предыдущие 5 шагов.Если нет, то я должен указать, какие шаги пользователь выполнил, а какие ожидают.Для ожидающего я также добавляю URL, чтобы пользователь мог легко перенаправить.

Проблема в том, что я повторяю каждый шаг, но из-за NG RX он не ждет завершения действия и перехода к следующемушаг.Я не могу определить, действительно ли предыдущие шаги завершены или нет.

Я использую технологии NG RX Action, Reducer и Effect.В любом случае я могу подождать цикл для завершения первого действия.После того, как первое действие выполнено, а затем возьмите второй элемент из массива.

// 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

Примечание: Извините, у меня нет фактического кода для обмена здесь.

1 Ответ

1 голос
/ 14 мая 2019

Я думаю, что лучший способ сделать это через охрану маршрутизатора, см. пример-приложения для примера.

@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']))
    );
  }
}

У Тодда Мотто также есть отличный пост на эту тему на ultimatecourses .

...