Почему <app-root> отображает другой <app-root> внутри него, который содержит мой перенаправленный компонент?

У меня есть лениво загруженное многомодульное приложение Angular 7.2.2, которое, похоже, создает копию основного AppComponentшаблон внутри себя, затем рендеринг маршрутизируемого компонента в этом.

Вот моя попытка завершить, но краткую преамбулу (я не могу воспроизвести это в plunkr). Пожалуйста, спросите любые детали, которые я пропустил.

Преамбула

у меня есть index.html файл, который содержит обычный HTML, и <app-root> элемент в его <body>, Это единственное место в проекте, которое app-root тег появляется. На этот файл ссылаются в angular.json"s projects.app.architect.build.options.index имущество.

Главный AppComponent объявлен как

@Component({
  selector: 'app-root',
  template: `
    <router-outlet></router-outlet>
    <message-banner [show]="showMessage" [message]="message"></message-banner>
  `,
  providers: [AuthenticationService, AuthenticationGuard, MessagingService]
})

Остальная логика в AppComponent просто опосредует show а также message контент для уведомлений всего приложения. У меня нет подключения к маршрутизатору и прямой манипуляции с DOM.

мой main.ts загружает приложение как обычно

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';
import { environment } from './environments/environment';

import { hmrBootstrap } from './hmr';

if (environment.production) {
  enableProdMode();
}

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

if (environment.hmr && module['hot']) {
  hmrBootstrap(module, bootstrap);
}
else {
  bootstrap().catch(err => console.log(err));
}

Из следующего AppModule

@NgModule({
  imports: [
    appRoutes,
    BrowserAnimationsModule,
    BrowserModule,
    CommonModule,
    FormsModule,
    HttpClientModule,
    HttpClientXsrfModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
    SharedGenericModule
  ],
  declarations: [
    AppComponent,
    MessageBannerComponent
  ],
  providers: [
    { provide: APP_BASE_HREF, useValue: '/' },
    appRoutingProviders,
    ChoosePasswordGuard,
    LoadingBarService,
    Title,
    UserService
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  bootstrap: [AppComponent]
})

export class AppModule {}

Эта проблема

Как только приложение стабилизируется, полученный DOM будет выглядеть так:

<body>
  <app-root ng-version="7.2.2">

    <router-outlet></router-outlet>

    <app-root>
      <router-outlet></router-outlet>
      <default-routed-component _nghost-c0>...</default-routed-component>
      <message-banner ng-reflect-show="true" ng-reflect-message="[object Object]">...</message-banner>
    </app-root>

    <message-banner ng-reflect-show="true" ng-reflect-message="[object Object]">...</message-banner>

  </app-root>
</body>

Обратите внимание, что внутренний <app-root> не украшен ng-version,

Кроме того, я могу только программно общаться с внутренним <message-banner>внешний кажется отключенным. Но сообщения, сгенерированные до загрузки первого маршрута (до стабилизации приложения), отправляются в оба экземпляра баннера сообщения.

Вопросы

Почему мое приложение создает два экземпляра <app-root>с двумя <router-outlets>, но только используя один из них. Как я могу предотвратить это?

Мне нужно сохранить одно приложение <message-banner>, но я, очевидно, хочу именно такой. Если бы не дублирование этого компонента, это могло бы быть просто таинственным неудобством - в противном случае приложение работает превосходно во всех отношениях.

2 ответа

Ответ предельно очевиден в ретроспективе.

Основной AppComponent - который содержал только приложение <router-outlet> и общий код, который я хотел использовать в приложении - он был загружен из основного модуля AppModule и во второй раз был создан маршрутизатором в качестве компонента маршрута по умолчанию, который затем загружал функциональные модули как дочерние маршруты.

Исправление было просто удалить AppComponent и дочернюю маршрутизацию; так изменить app.routes.ts от

const routes: Routes = [
  {
    path: '',
    redirectTo: 'shop',
    pathMatch: 'full'
  },
  {
    path: '',
    component: AppComponent,
    children: [
      {
        path: 'shop',
        data: { key: 'shop' },
        loadChildren: "./modules/shop.module#ShopModule",
        pathMatch: 'full'
      },
  ...
  }
]

в

const routes: Routes = [
  {
    path: '',
    redirectTo: 'shop',
    pathMatch: 'full'
  },
  {
    path: 'shop',
    data: { key: 'shop' },
    loadChildren: "./modules/shop.module#ShopModule",
    pathMatch: 'full'
  },
  ...
]

Я новичок в этом, я не понимаю, почему, но вы должны создать другой основной компонент с другим <router-outlet>тег (кроме app.component.ts — это основной компонент) и вызывать его из родительских маршрутов. Например

Шаг первый: ng генерирует c layout/inicio

      App
 - Layout
     -inicio.component.ts
     -inicio.component.html

А вот и магия =>

код: inicio.component.ts

      const routes: Routes = [
  {
    path: '',
    component: InicioComponent,
    children: [
      {
        path: 'shop',
        data: { key: 'shop' },
        loadChildren: "./modules/shop.module#ShopModule",
        pathMatch: 'full'
      },
      {
        path: 'car/:id',
        data: { key: 'car' },
        loadChildren: "./modules/car.module#CarModule",
        pathMatch: 'full'
      },
      {
        // This one has child routes, which I will add if needed
        path: 'workOrder',
        data: { key: 'workOrder' },
        loadChildren: "./modules/workOrder.module#WorkOrderModule",
      }
      // And many more
    ]
  }
]

Если ваш модуль ленивых загрузок настроен правильно, он должен работать. Я надеюсь, что это может помочь вам, привет из Чили.

Другие вопросы по тегам