Создайте путь Routes, который загружает определенный компонент на основе условия - PullRequest
0 голосов
/ 20 октября 2019

Я хочу загрузить отдельные компоненты для одинаковых структурированных путей.

Средства :

example.com / what-post-slug -> LoadКомпонент публикации
example.com/whwhat-page-slug -> Загрузка компонента страницы
example.com/hello-i-am-a-string -> Загрузка компонента публикации (поскольку этот слаг относится к записи)
example.com/about-us -> Загрузить компонент страницы (поскольку этот слаг относится к странице)

Зачем мне это делать?

Кто-то может подумать : эй, но почему бы вам просто не определить два префиксных различных пути, для чего существуют пути?

Ответ таков:: Я создаю (кстати, с открытым исходным кодом ) угловую тему WordPress, и я хочу, чтобы маршрутизация была тем, что решит пользователь, без принудительного создания какой-либо жестко заданной структуры.

В одномиз множества возможностей, сообщений и страниц (если вы не знаете WordPress, просто знайте, что это два разных типа контента, которые я хочу использоватьнезависимые Модули и Компоненты для) могут совместно использовать слагов на корневом уровне.

И на первый взгляд, я не могу знать, относится ли слаг к сообщению или странице или к чему-то еще (поэтому UrlMatcher здесь не может помочь).

Думал ли я о решении?

Да, из трех.

Первое решение

Я мог бы создать компонент Wrapper, который будет загружаться для универсального маршрута, а затем внутри этого компонента сделать что-то вроде:

<whatever-a-component *ngIf="showComponentA()"><whatever-a-component>
<whatever-b-component *ngIf="showComponentB()"></whatever-b-component>

И позволить компоненту Wrapper выполнить всю логику.

Это добавляет дополнительный промежуточный компонент в игру.

Второе решение

Используйте распознаватель для перехвата, а затем выполните всю логику в распознавателе.

Проблема в том, что мне нужно подписаться на http-сообщение, чтобы узнать, с каким типом контента я имею дело, и, поскольку метод Resolver resol () должен возвращать Observable, подписывать там нехорошо.

Конечно, это работает, если яПовторите заполнитель, наблюдаемый некоторое время, например:

// ... inside resolve()
// Force an observable return to allow suscriptions take their time
return Observable.create(observer => {
  setTimeout(() => {
    console.log("Resolver observable is done");
    observer.complete();
  }, 15000);
});

... или если я передам свою подписку с mergeMap() и верну ПУСТО, когда получу результаты от моей подписки.

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

Это не кажется мне очень чистым подходом.

Третье решение

Просто загрузите обычный компонент Dispatcher, который выполнит все проверки на OnInit(), а затем перейдите к «секретному» специфичному для компонента URL-адресу, но с использованием { skipLocationChange: true }, поэтомуУ пользователя будет правильный маршрут, а также будет загружен правильный компонент.

Но, опять же, это добавляет дополнительный промежуточный компонент в игру.

Я думаю, что это самое чистое решение, так как примодуль «Маршрутизация приложений». Я могу сделать что-то вроде:

{
path: 'wp-angular/view-post/:id',
loadChildren: () => import('./view-post/view-post.module').then(m => m.ViewPostModule)
},
{
path: 'wp-angular/view-page/:id',
loadChildren: () => import('./view-page/view-page.module').then(m => m.ViewPageModule)
}

Итак, эти модули будут загружаться с отложенной загрузкой, только если пользователь действительно посетит один из этих двух типов контента.

AКроме того, этот компонент типа контента уже будет доступен, если пользователь затем посетит второй контент того же типа.

И тот факт, что я могу использовать { skipLocationChange: true }, позволит сохранить путь, как ожидалось.

Кроме того, это позволяет отображать отзывы о загрузке навигации без необходимости подписки на события маршрутизатора.

Вопрос

Что бы вы сделали и почему?

Возможно, мне не хватает какой-то волшебной функции Angular, которая позволяет делать это прямо в точку.

1 Ответ

1 голос
/ 22 октября 2019

После того, как у меня возникла похожая проблема, и я решил ее следующим образом:

Вы можете использовать Модуль, который обрабатывает, какой компонент должен быть загружен, предоставляя МАРШРУТЫ RouterModule с помощью поставщика useFactory из Angular.

Код может быть примерно таким:

// HandlerModule

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    RouterModule
  ],
  providers: [
    {
      provide: ROUTES,
      useFactory: configHandlerRoutes,
      deps: [CustomService],
      multi: true
    }
  ]
})

export class HandlerModule {}

export function configHandlerRoutes(customService: CustomService) {
  let routes: Routes = [];
  if (customService.whatever()) {
    routes = [
      {
        path: '', component: AComp
      }
    ];
  } else {
    routes = [
      {
        path: '', component: BComp
      }
    ];
  }
  return routes;
}

Тогда в вашем AppRoutingModule модулем пути '' будет HandlerModule:

// AppRoutingModule

 {
    path: '',
    loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)
}

После этого в CustomService необходимо обновить Router.config, когда значение, предоставляющее метод .whever (), изменится, поскольку приложение будет загружать только тот компонент, который был загружен в первый раз. Это связано с тем, что функция «configHandlerRoutes», используемая поставщиком useFactory в HandlerModule, выполняется только при первом переходе к пути «», после чего Angular Router уже знает, какой компонент он должен загрузить.

В заключение в CustomService вы должны сделать:

  export class CustomService {
  private whateverValue: boolean;
  constructor(private router: Router) {
  }

  public whatever(): boolean {
    return this.whateverValue;
  }

  public setWhatever(value: boolean): void {
    const previous = this.whateverValue;
    this.whateverValue = value;
    if (previous === this.whateverValue) {
      return;
    }
    const i = this.router.config.findIndex(x => x.path === '');
    this.router.config.splice(i, 1);
    this.router.config.push(
      {path: '', loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)}
    );
  }
}

Вот и все. Я использовал путь "" для примера, но вы можете использовать любой путь, который вам нужен.

Также вы можете использовать тот же подход, если хотите загружать модули вместо компонентов.

Если выхочу еще одну ссылку, вот статья, где они используют тот же подход: https://medium.com/@german.quinteros/angular-use-the-same-route-path-for-different-modules-or-components-11db75cac455

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...