Search code examples
angulartypescriptangular-router

"NG8001: 'router-outlet' is not a known element" in Angular


I'm new to Angular. This is my hierarchy tree:

src/
├─ app/
│  ├─ containers/
│  │  ├─ default-layout/
│  │  │  ├─ default-layout.component.html
│  │  │  ├─ default-layout.component.ts
│  │  │  ├─ index.ts
│  │  ├─ index.ts
│  ├─ shared/
│  ├─ features/
│  │  ├─ login/
│  │  │  ├─ components/
│  │  │  ├─ services/
│  │  │  ├─ login.component.html
│  │  │  ├─ login.component.ts
│  │  │  ├─ login.module.ts

In default-layout.component.html i use

<div class="container-fluid">
  <ng-http-loader
    backgroundColor="#EB2E2C"
    spinner="sk-wave">
  </ng-http-loader>
  <router-outlet></router-outlet>
</div>

But i have this issue:

NG8001: 'router-outlet' is not a known element:

even if i'm importing RouterModule in app.routes.ts:

    import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// Import Containers
import { DefaultLayoutComponent } from './containers';

import { LoginComponent } from './features/login/login.component';
import { AuthguardService } from './shared/services/authguard.service';

export const routes: Routes = [
    /* {
       path: '',
       redirectTo: 'dashboard',
       pathMatch: 'full',
     },*/
    {
        path: '', redirectTo: '/login', pathMatch: 'full'
    },
    {
        path: 'login',
        component: LoginComponent,
        data: {
            title: 'Login Page'
        }
    },
    {
        path: '',
        component: DefaultLayoutComponent,
        canActivateChild: [AuthguardService],
        data: {
            title: 'Home'
        },
        children: [
        ]
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule {
}

and importing AppRoutingModule in app.module.ts (+ declaration of DefaultLayoutComponent where RouterModule is needed):

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule, HashLocationStrategy, LocationStrategy } from '@angular/common';

import { AppComponent } from './app.component';

// Import containers
import { DefaultLayoutComponent } from './containers/default-layout';

import { LoginComponent } from './features/login/login.component';

import { BreadcrumbModule, FooterModule, HeaderModule, SidebarModule, } from '@coreui/angular';


// Import routing module
import { AppRoutingModule } from './app.routes';

import { AuthguardService } from './shared/services/authguard.service';
import { LoginService } from './features/login/services/login.service';
import { ModalModule, BsModalService } from 'ngx-bootstrap/modal';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { NgHttpLoaderModule } from 'ng-http-loader';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { CollapseModule } from 'ngx-bootstrap/collapse';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { BaseChartDirective } from 'ng2-charts';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    DefaultLayoutComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    CommonModule,
    AppRoutingModule,
    BreadcrumbModule,
    FooterModule,
    HeaderModule,
    SidebarModule,
    BsDropdownModule.forRoot(),
    TabsModule.forRoot(),
    BsDatepickerModule.forRoot(),
    CollapseModule.forRoot(),
    ModalModule.forRoot(),
    NgxDatatableModule,
    BaseChartDirective,
    NgHttpLoaderModule.forRoot()
  ],
  providers: [AuthguardService, LoginService, BsModalService,
    {
      provide: LocationStrategy,
      useClass: HashLocationStrategy
    }, provideHttpClient(withInterceptorsFromDi())],
  bootstrap: [AppComponent]
})
export class AppModule {
}

default-layout.component.ts:

import {Component} from '@angular/core';
import {navItems} from '../../_nav';
import {Router} from '@angular/router';
import {LoginService} from '../../service/login.service';
import {CookieService} from 'ngx-cookie-service';

@Component({
  selector: 'app-dashboard',
  templateUrl: './default-layout.component.html'
})
export class DefaultLayoutComponent {
  public navItems = navItems;
  public sidebarMinimized = true;
  private changes: MutationObserver;
  public element: HTMLElement = document.body;
  public listServer = [];

  constructor(
    private router: Router,
    private loginService: LoginService,
    private cookieService: CookieService) {

    this.changes = new MutationObserver((mutations) => {
      this.sidebarMinimized = document.body.classList.contains('sidebar-minimized');
    });

    this.changes.observe(<Element>this.element, {
      attributes: true
    });
    this.getStatusServer();
  }

  openDashboard() {
    this.router.navigate(['dashboard']);
  }

  getStatusServer() {
    // this.listServer = [{name:'L1',status:false},{name:'L2',status:true},{name:'L3',status:true},{name:'L4',status:true}]
    this.loginService.getStatusServer()
      .subscribe(res => {
          this.listServer = res;
        },
        err => {
        }
      );
  }


  getClassStatusServer(server) {
    return server.status ? 'divStatusServer text-center serverTrue' : 'divStatusServer text-center serverFalse';
  }

  logout() {
    this.loginService.logout()
      .subscribe(res => {
          console.log('LOGOUT OK');
          this.cookieService.deleteAll();
          this.router.navigate(['login']);
        },
        err => {
          console.log('LOGOUT ERROR');
          this.cookieService.deleteAll();
          this.router.navigate(['login']);
        }
      );
  }

}

app.components.ts:

    import { Component } from '@angular/core';
//import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  //imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'CC';
}

main.ts:

import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));
enter code here

main.server.ts:

import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';

const bootstrap = () => bootstrapApplication(AppComponent, config);

export default bootstrap;

Solution

  • You are mixing modular and standalone methodologies of Angular, that is the root cause of the problem.

    Modular approach docs

    Standalone approach docs

    The main.ts for modular should look something like below.

    main.server.ts

    export { AppServerModule as default } from './app/app.module.server';
    

    main.ts

    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    
    import { AppModule } from './app/app.module';
    
    
    platformBrowserDynamic().bootstrapModule(AppModule)
      .catch(err => console.error(err));
    

    Also remove the standalone: true in app.component.ts

       import { Component } from '@angular/core';
    //import { RouterOutlet } from '@angular/router';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrl: './app.component.scss'
    })
    export class AppComponent {
      title = 'CC';
    }
    

    I am leaning toward modular approach, since most of the code is modular. But it's your personal choice. I am providing two Stackblitz, one for modular and one for standalone; please use these code references and try to fix your issues, there are multiple.

    Modular SSR stackblitz

    Standalone SSR Stackblitz