Угловой распознаватель не обновляет и не перезагружает данные, несмотря на то, что для runGuardsAndResolvers установлено "всегда"?

У меня есть набор угловых маршрутов с перечнем объектов, с двумя дочерними маршрутами для создания такого объекта и редактирования существующего объекта. Список лиц имеет resolver прикреплен к нему для предварительной выборки данных для компонента перед его отображением. Эти маршруты могут быть обобщены следующим образом, смотрите далее, как эти маршруты описаны в коде.

  • индекс: /items
  • Создайте: /items/create
  • редактировать: /items/:itemId/edit

Однако, если я в /items/create и успешно создать элемент, перейдя "назад" к /items или любой редактировать маршрут, или даже вернуться к / не приведет к тому, что мой распознаватель получит обновленные данные, как я ожидал. Это несмотря на то, что runGuardsAndResolvers свойство установлено на "всегда". Насколько я понимаю, это свойство должно включать функциональность, которую я ищу.

Почему это так, и как я могу включить нужную функциональность, не делая при этом что-то вроде подписки на события маршрутизатора в моем компоненте и дублирования логики.

Маршруты

const itemRoutes: Routes = [
    {
        path: '', // nb: this is a lazily loaded module that is itself a child of a parent, the _actual_ path for this is `/items`. 
        runGuardsAndResolvers: 'always',
        component: ItemsComponent,
        data: {
            breadcrumb: 'Items'
        },
        resolve: {
            items: ItemsResolver
        },
        children: [
            {
                path: 'create',
                component: CreateItemComponent,
                data: {
                    breadcrumb: 'Create Item'
                }
            },
            {
                path: ':itemId/edit',
                component: EditOrArchiveItemComponent,
                data: {
                    breadcrumb: 'Editing Item :item.name'
                },
                resolve: {
                    item: ItemResolver
                }
            }
        ]
    }
];

ItemsResolver

@Injectable()
export class ItemsResolver implements Resolve<ItemInIndex[]> {
    public constructor(public itemsHttpService: ItemsHttpService, private router: Router) {}

    public resolve(ars: ActivatedRouteSnapshot, rss: RouterStateSnapshot): Observable<ItemInIndex[]> {
        return this.itemsHttpService.index().take(1).map(items => {
            if (items) {
                return items;
            } else {
                this.router.navigate(['/']);
                return null;
            }
        });
    }
}

ItemsHttpService

(Размещение по запросу)

@Injectable()
export class ItemsHttpService  {

    public constructor(private apollo: Apollo) {}

    public index(): Observable<ItemInIndex[]> {
        const itemsQuery = gql`
            query ItemsQuery {
                items {
                    id,
                    name
                }
            }
            `;

        return this.apollo.query<any>({
            query: itemsQuery
        }).pipe(
            map(result => result.data.items)
        );
    }
}

3 ответа

Решение

Прежде всего.

Это не то, как вы должны использовать Resolver,

Вы должны использовать Resolver только если это необходимо для вашего маршрута, что необходимые данные существуют. Поэтому Resolver имеет смысл, когда у вас есть маршрут для выделенного фрагмента данных, и вы хотите убедиться, что эти данные существуют, прежде чем продолжить загрузку компонента.

Давайте возьмем ваше приложение Item в качестве примера и столкнемся с проблемой с точки зрения пользователя.

/Предметы

Пользователь переходит к /items и то, что он увидит первым, - ничто. Это потому, что Resolver извлекает все элементы, прежде чем пользователь сможет добраться до компонента. Только после того, как распознаватель извлек все элементы из API, пользователь получает делегирование ItemsComponent,

Но это не обязательно и плохой пользовательский опыт.

Почему бы не делегировать пользователя напрямую ItemsComponent, Если у вас есть, к примеру, потрясающая таблица с множеством кнопок и фантастическим классным CSS, вы можете дать вашему приложению время на рендеринг этих элементов, пока Service извлекает данные из API. Чтобы указать пользователю, какие данные загружаются, вы можете показывать хороший индикатор прогресса (-bar) внутри таблицы до тех пор, пока данные не поступят.

/ пункты / создать

Тоже самое. Пользователь должен ждать, пока Resolver получил все данные из вашего API, прежде чем он сможет достичь CreateComponent, Должно быть понятно, что это излишнее извлечение всех элементов, только элемент может создать только пользователь. Таким образом, нет необходимости в Resolver

/ Пункты /: Itemid/ редактировать

Это лучшее место для Резольвера. Пользователь должен иметь возможность маршрутизировать к этому компоненту, если и только если элемент существует. Но так как вы определили Resolver для извлечения всех элементов, когда активируется один из ваших дочерних маршрутов, пользователь сталкивается с тем же плохим пользовательским интерфейсом, что и с предыдущими маршрутами.

Решение

Удалите ItemsResolver из ваших маршрутов.

const routes: Routes = [
  {
      path: '',
      component: ItemsComponent,
      children: [
        {
          path: '',
          component: ItemsListComponent,
          data: {
            breadcrumb: 'Items'
          },
        },
        {
          path: 'create',
          component: CreateItemComponent,
          data: {
            breadcrumb: 'Create Item'
          },
        },
        {
          path: ':itemId/edit',
          component: EditOrArchiveItemComponent,
          data: {
            breadcrumb: 'Editing Item :item.name'
          },
          resolve: {
            item: ItemResolverService
          }
        }
      ]
  }
];

Вы можете определить BehaviorSubject в вашем ItemsService который содержит ваши последние извлеченные элементы как кеш. Каждый раз, когда пользователь возвращается из создания или редактирования в ItemsComponent Ваше приложение может немедленно визуализировать кэшированные элементы, а служба может синхронизировать элементы в фоновом режиме.

Я реализовал небольшой рабочий пример приложения: https://stackblitz.com/github/SplitterAlex/stackru-48640721

Заключение

Resolver имеет смысл только при редактировании маршрута предметов.

использование Resolver осторожно!

Если вы переходите к одной и той же записи маршрута, angular повторно использует маршрут, поэтому распознаватели не выполняются повторно. Чтобы изменить это поведение, вы можете перезаписать shouldReuseRoute из routeReuseStrategy.

      public ngOnInit(): void {

     this.router.routeReuseStrategy.shouldReuseRoute = () => false;

}

Я не знаю, как решить вашу конкретную проблему, но я работал под охраной на Angular, вот так, я мог бы помочь вам:

  • Изменить:

routing.module.ts

path: '/items/create', canActivate: [AuthGuard]...

AuthGuard разрешает доступ к этому URL-адресу... Это пользовательская охрана.

  • Создайте

file.guards.ts

// Imported at providers on your app.module.ts file

export class AuthGuard implements CanActivate {

  constructor(){ }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): any {
     // create a function which returns boolean
     // allow your access to this url
  }
}
Другие вопросы по тегам