udemy.angular/docs/routing.md
2021-12-15 10:17:07 +01:00

5.5 KiB

Routing

Routes are a method to replace part of a page and display in the URL the desired component.

Setup and Loading Routes

In the app.module.ts we need to register all the needed routes

import { Routers, RouterModule } from '@angular/router';

const appRoutes: Routes = [
    { path: '', component: HomeComponent }, 
    { path: 'users', component: UsersComponent }, //localhost:4200/users
    { path: 'servers', component: ServersComponent }, 
];

@ngModule({
    imports: [
        ...,
        RouterModule.forRoot(appRoutes)
    ]
})

app.component.html

    ...
        <!-- here we mark where we want to have the component rendered -->
        <router-outlet></router-outlet>
    ...

With every klicked Link, a new request is sent to the server and the page is refreshed.

Bad implementation

<ul class="nav nav-tabs">
    <li role="presentation" class="active"><a href="/">Home</a></li>
    <li role="presentation"><a href="/servers">Servers</a></li>
    <li role="presentation"><a href="/users">Users</a></li>
</ul>

Correct implementation

<ul class="nav nav-tabs">
    <li role="presentation" class="active"><a routerLink="/">Home</a></li>
    <li role="presentation"><a routerLink="/servers">Servers</a></li>
    <li role="presentation"><a routerLink="/users">Users</a></li>
</ul>

If there is more then one level the routeLink will look like this and it's called array-notation.

<ul class="nav nav-tabs">
    <li role="presentation" class="active"><a routerLink="/">Home</a></li>
    <li role="presentation"><a routerLink="/servers">Servers</a></li>
    <li role="presentation"><a [routerLink]="['/users', 'editUser'">Users Edit</a></li>
</ul>

Result: https://domain.tld/user/editUser

Relative path: servers → Relative path will be added to the actual path.

Absolute path: /servers

routerLinkActive="active"

With active is the CSS-Class to style the active nav element.

<ul class="nav nav-tabs">
    <li role="presentation" 
        routerLinkActive="active"><a routerLink="/">Home</a></li>
    <li role="presentation" 
        routerLinkActive="active"><a routerLink="/servers">Servers</a></li>
    <li role="presentation" 
        routerLinkActive="active"><a routerLink="/users">Users</a></li>
</ul>

This method has a caviat, that angular analyzes the URL and the Home is allways active because in every route contains the domain.tld/

By adding the [routerLinkActiveOptions]="{exact: true}" configuration, we can fix this issue. Necessary only on the /

<ul class="nav nav-tabs">
    <li role="presentation" 
        routerLinkActive="active"
        [routerLinkActiveOptions]="{exact: true}"><a routerLink="/">Home</a></li>
    ...
</ul>

Trigger the routing programmatically

In any Component ts

import { Router } from '@angular/router'

export class HomeComponent {
    // inject of the router
    constructor(private router: Router) {}

    onLoadServer() {
        // some calc
        this.router.navigate(['servers']);
    }
}

Passing parameter to Router

:id wil be dynamically assigned.

const appRoutes: Routes = [
    { path: '', component: HomeComponent }, 
    { path: 'users', component: UsersComponent }, //localhost:4200/users
    { path: 'users/:id', component: UserComponent }, //localhost:4200/users/5
    { path: 'servers', component: ServersComponent }, 
    { path: 'servers/:id', component: ServerComponent }, 
];

Fetching Route Parameters

The data will be fetched from the URL https://domain.tld/users/1/Max

overview

id = 1

name = Max

this.route.snapshot.params.subscribe(
    (params: Params) => {
        this.user.id = params['id'];
        this.user.name = params['name'];
    } 
);

If a route will change, the content of the Component will stay the same, because was allredy instanciated. If we want that the Component will update if the URL updates the route.params has to be used. It is of type observable and will act as asynchronus to load the data if and when the URL is changed.

If an instance gets destroyed and contains an observable which the component is subscribed to, is good practice to unsubscribe from it.

ngOnDestroy() {
    this.paramsSubscription.unsubscribe();
}

Passing query parameters and fragments

servers.component.html

<a
    [routerLink]="['/servers', server.id]"
    [queryParams]="{allowEdit: server.id === 3 ? '1' : '0'}"
    fragment="loading"
    href="#"
    class="list-group-item"
    *ngFor="let server of servers">
    {{ server.name }}
</a>

Retieving query parameters and fragments

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';


@Component({
  selector: 'app-edit-server',
  templateUrl: './edit-server.component.html',
  styleUrls: ['./edit-server.component.css']
})
export class EditServerComponent implements OnInit, CanComponentDeactivate {
  server: {id: number, name: string, status: string};
  serverName = '';
  serverStatus = '';

  constructor(private serversService: ServersService,
              private route: ActivatedRoute) {
  }

  ngOnInit() {
    console.log(this.route.snapshot.queryParams);
    console.log(this.route.snapshot.fragment);
    this.server = this.serversService.getServer(id);
    this.serverName = this.server.name;
    this.serverStatus = this.server.status;
  }