Search code examples
angularangular-routingangular-module

Angular Routing selector "app-home" did not match element


I want to prevent my initial component being loaded twice. I am trying to use a default/empty component to avoid the AppComponent being loaded withing the AppComponent The empty component would be the starting point, to where other components are being loaded in at users command.

I'm still figuring out Angular Routing, but as I understand the router-outlet loads in modules dynamically, always starting at the AppComponent by default?

I thought by setting a empty Homecomponent it would break the AppComponent-loop

What am I doing wrong? Is this all the code that is relevant to the problem?

My Index.html

<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="utf-8" />          
      <base href="/" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />   
    </head>
    <body>
      <app-root>
         Loading...
      </app-root>
    </body>
</html>

My app.component.html

<app-nav-menu></app-nav-menu>    //navigation that is always shown
<router-outlet></router-outlet>  

The app Routes:

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: 'home', pathMatch: 'full' }
];
@NgModule({
  imports: [
    RouterModule.forRoot(routes),
    HomeModule,  
    AccountModule,
    OtherModules
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

My home.html is just an empty html-file

My home module

@NgModule({
  declarations: [    
  ],
  imports: [
    CommonModule,     
    RouterModule.forChild([  
       { path: 'feed', loadChildren: () => import('./../home/feed/feed.module')
                                .then(x => x.FeedModule)},

       { path: 'search', loadChildren: () => import('./../home/searchresults/search.module')
                                .then(x => x.SearchModule)}  

    ]),
    SharedModule,
    OtherModules    
  ],
  exports: [
    CommonModule,
    RouterModule,    
    SharedModule,
    OtherModules     
  ],
  providers: [
    LoginService
  ]
})
export class HomeModule { }

App module:

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,     
    FirstLoadedComponent,    
    AuthCallbackComponent    
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    AppRoutingModule,
    SharedModule,
    HttpClientModule,
    ReactiveFormsModule,
    FormsModule,
    CoreModule,
    OtherModules
  ],
  exports: [
  ...
  ],
  providers: [
  ...
  ],
  bootstrap: [
    //HomeComponent //gives error
    //FirstLoadedComponent //gives error
    AppComponent //triggers a <app-root>-inception resulting in double load of first component
  ],
  entryComponents: [
  ...
  ]
})
export class AppModule {

}

When I bootstrap the AppComponent in the AppModule, it triggers a second AppModule so the first loaded Component is shown twice.

When I want to bootstrap HomeComponent (empty html) or the first loaded component I get the error:

The selector "app-home" did not match any elements at DefaultDomRenderer2.selectRootElement 
(platform-browser.js:661)

How is this possible when I declare the HomeComponent (with the selector app-home) in the root AppModule? Am I overwriting good logic with wrong logic somewhere? The cascade can be a bit confusing.

*Edit: I did not bootstrap all 3 components at the same time, just one by one and added in comment what the behaviour was.

Thanks for input


Solution

  • Lets start with the statement

    I'm still figuring out Angular Routing, but as I understand the router-outlet loads in modules dynamically, always starting at the AppComponent by default?

    That is partially true. In your AppModule you have various arrays

    declarations—this application's lone component.

    imports—import BrowserModule to have browser specific services such as DOM rendering, sanitization, and location.

    providers—the service providers.

    bootstrap—the root component that Angular creates and inserts into the index.html host web page.

    Basically any component you load in the bootstrap array will be loaded,

    Next thing you need to note is that as long as you don't declare a component in the declarations array there is no way angular will know about the component and will throw the error

    So to solve your multiple loading remove the extra components from the boostrap array

    bootstrap: [AppComponent],
    

    Now if you do not need the HomeComponent to be loaded you need to also lazyload this as a module

    const routes: Routes = [
      {  
         path: 'home', 
         loadChildren: () => import('home/home.module.ts').then(
         m => m.HomeModule
        ) 
      },
      { path: '', redirectTo: 'home', pathMatch: 'full' }
    ];
    

    Now you need to remove HomeComponent from the declaration array of the AppModule and add it to the declaration array of HomeModule