Search code examples
angularangular-routing

Angular - Routes aren't working - Error: NG04002: Cannot match any routes. URL Segment


Sorry for my bad english :/ I'm trying to build a simple online shop app with Angular, but so far when I try to access the two routes (home and 'carrinho' [portuguese for cart]) it gives me the error 'Error: NG04002: Cannot match any routes. URL Segment' and the browser redirects to localhost:4200 and not to the route I desire. The localhost:4200/carrinho should show the 'carrinho works!' sentence just to be sure thats working, but instead I have the error and redirects me to localhost:4200, same for home. So, any of these two are working. I'm facing bad things these days, so my attention may have ignored something, I tried to find whatever could be wrong and fix it, even visiting several Stack Overflow Threads here, but couldn't.

app-routing-module.ts - (src/app) folder

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CarrinhoComponent } from './pages/carrinho/carrinho.component'
import { HomeComponent } from './pages/home/home.component';

const routes: Routes = [
  {
    path: 'home',
    component: HomeComponent,
  },
  {
    path: 'carrinho',
    component: CarrinhoComponent,
  },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
];

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

app-module.ts - (src/app) folder

import { NgModule } from '@angular/core';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatGridListModule } from '@angular/material/grid-list';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { MatMenuModule } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatTreeModule } from '@angular/material/tree';
import { MatListModule } from '@angular/material/list';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTableModule } from '@angular/material/table';
import { MatBadgeModule } from '@angular/material/badge';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { HeaderComponent } from './components/header/header.component';
import { HomeComponent } from './pages/home/home.component';
import { ProductsHeaderComponent } from './pages/home/components/products-header/products-header.component';
import { FiltersComponent } from './pages/home/components/filters/filters.component';
import { CarrinhoComponent } from './pages/carrinho/carrinho.component';


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    HeaderComponent,
    ProductsHeaderComponent,
    FiltersComponent,
    CarrinhoComponent,
  ],

  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatSidenavModule,
    MatGridListModule,
    MatMenuModule,
    MatButtonModule,
    MatCardModule,
    MatIconModule,
    MatExpansionModule,
    MatTreeModule,
    MatListModule,
    MatToolbarModule,
    MatTableModule,
    MatBadgeModule,
    MatSnackBarModule,
    HttpClientModule
  ],
  exports: [
    MatSidenavModule,
    MatGridListModule
  ]
})
export class AppModule { }

home-component.ts

import { Component } from '@angular/core';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatGridListModule } from '@angular/material/grid-list';
import { ProductsHeaderComponent } from './components/products-header/products-header.component';
import { FiltersComponent } from './components/filters/filters.component';
import { ProductBoxComponent } from './components/product-box/product-box.component';

const ROWS_HEIGHT: { [id: number]: number } = { 1: 400, 3: 335, 4: 350 };

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [ProductBoxComponent, FiltersComponent, ProductsHeaderComponent, MatSidenavModule, MatGridListModule],
  templateUrl: './home.component.html',
  styleUrl: './home.component.css'
})
export class HomeComponent {
  cols = 3;

  rowHeight = ROWS_HEIGHT[this.cols];

  categoria: string | undefined;

  constructor(){

  }

  ngOnInit(): void {

  }

  onColumnsCountChange(numCols: number): void {
    this.cols = numCols;
    this.rowHeight=ROWS_HEIGHT[this.cols];
  }

  onShowCategoria(novaCategoria: string): void {
    this.categoria = novaCategoria;
  }
}

app-component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { HeaderComponent } from './components/header/header.component';
import { HomeComponent } from './pages/home/home.component';
import { CarrinhoComponent } from './pages/carrinho/carrinho.component';

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

app-component.html


      <app-header></app-header>
      <router-outlet></router-outlet>
      <app-home></app-home>

header-component.html (with a button using routerLink for carrinho (cart) route)

<mat-toolbar class="mat-toolbar-custom max-w-7x1-mx-auto border-x justify-between">
  <a routerLink="home">Conheça a Loja</a>
  <button mat-icon-button [matMenuTriggerFor]="menu">
    <mat-icon
    [matBadge] = "1"
    [style.color]="'rgb(22, 99, 115)'"
    >shopping_cart</mat-icon>
  </button>
  <mat-menu #menu="matMenu">
    <div class="p-3 divide-y divide-solid">
      <div class="pb-3 flex justify-between">
      <span class="mr-16">1 items</span>
      <br>
      <a routerLink="carrinho">Consultar Carrinho</a>
    </div>
    <div class="p-4">
      <div class="flex justify-between font-light mb2">
      Keyboard x1
      <span class="font-bold">{{ '150' | currency: 'BRL' }}</span>
      </div>
      <div class="flex justify-between font-light mb2">
        Keyboard x1
        <span class="font-bold">{{ '150' | currency: 'BRL' }}</span>
      </div>
      <div class ="flex justify-between py-3 font-light">
        Total:
        <span class="font-bold">{{ '300' | currency: 'BRL'}}</span>
      </div>
      <div class="pt-3 flex justify-between">
        <button class="bg-text-white-rounded-full w-10 h-10">
          <mat-icon>remove_shopping_cart</mat-icon>
        </button>
        <button routerLink="carrinho" class="bg-text-white-rounded-full w-10 h-10">
          <mat-icon>remove_shopping_cart</mat-icon>
        </button>
      </div>
    </div>
    </div>
  </mat-menu>
</mat-toolbar>

carrinho.component.html

<p>carrinho works!</p>

I expected to actually redirect to localhost:4200/home (showing what's inside the home-component) and localhost:4200/carrinho (showing what's inside the carrinho-component, which's 'carrinho works' just for test purposes).

Update: Just added the /home in index.html and now the home route works, but carrinho stays not working :(

Update2: I added the routes also in the app-routes.ts and it seems like /carrinho is now working, but is loading the components of the home page as well, and not only the ones from carrinho route, so not displaying correctly. Same for the home page.. (this page was right before like in picture 2 without the 'carrinho works')

https://i.sstatic.net/4jFcW.png
https://i.sstatic.net/VLtoZ.png
https://i.sstatic.net/rGDKx.png

Solved: Finally solved the problem with the route carrinho loading components from other routes using the changeDetectionStrategy Alpine used in his answer!


Solution

  • You need to change the app.component.html:

      <app-header></app-header>
      <router-outlet></router-outlet>
      <app-home></app-home>
    

    To

      <app-header></app-header>
      <router-outlet></router-outlet>
    

    The header contains the routerLink of the component, so it's displayed with router-outlet.

    This route config creates a static link to the route:

    // app-header

    <a routerLink="/home">Home component </a>
    <a routerLink="/carrinho">Carrinho component</a>
    

    // route configuration

    const routes: Routes = [
      {
        path: 'home',
        component: HomeComponent,
      },
      {
        path: 'carrinho',
        component: CarrinhoComponent,
      },
      { path: '', redirectTo: '/home', pathMatch: 'full' },
    ];
    

    Stackblitz Demo

    Note:

    • If the first segment begins with /, the router looks up the route from the root of the app.
    • If the first segment begins with ./, or doesn't begin with a slash, the router looks in the children of the current activated route.
    • If the first segment begins with ../, the router goes up one level in the route tree.